我们目前正在运行一个已花费一个小时执行的程序(但仍未完成),因此我们想知道我们是否可以改进程序代码以便它运行得更快。
我们的程序由两部分组成:首先我们需要更改字符串,因为我们使用JSON字典,并且数据具有相似的键(" track")用于所有项目 - 如果我们不这样做的话这样做,输出只给出第一个轨道。其次,我们需要将JSON数据打印到csv文件。
JSON文件的片段:(实际文件大约为900 MB)
{
"VV":{
"Version":1,
"Data":[
{
"track":[
{
"time":"YYYY-MM-DDTHH:MM:SS:MS",
"tl":{
"x":10,
"y":11
},
"br":{
"x":20,
"y":20
}
},
{
"time":"YYYY-MM-DDTHH:MM:SS:MS",
"tl":{
"x":12,
"y":15
},
"br":{
"x":22,
"y":23
}
}
],
"track":[
{
"time":"YYYY-MM-DDTHH:MM:SS:MS",
"tl":{
"x":30,
"y":39
},
"br":{
"x":40,
"y":45
}
},
{
"time":"YYYY-MM-DDTHH:MM:SS:MS",
"tl":{
"x":12,
"y":18
},
"br":{
"x":22,
"y":24
}
}
]
}
]
}
}
我们代码的第一部分:
with open(r'filename.json') as json_file:
fil = json_file.read()
i = 0
print i
while ('track' in fil) :
fil = fil.replace('track', 'tr'+str(i), 1)
i = i + 1
print i
input_data = json.loads(fil)
data_d = input_data['VV']['Data'][0]
第二部分:
with open(r'output.csv', 'wb') as csv_file:
writer = csv.writer(csv_file)
i = 0
for track, data in data_d.items():
i = i+1 # Track
for item in data:
#TRACK
item_values = []
item_values.append(i)
#DAY
#print item['time']
day = item['time'][8:10]
item_values.append(day)
#COORDINATEN
item_values.append(item['tl']['x'])
item_values.append(item['tl']['y'])
item_values.append(item['br']['x'])
item_values.append(item['br']['y'])
#TIME
time = item['time'][11:13]+item['time'][14:16]+item['time'][17:19]+item['time'][20:23]
item_values.append(time)
writer.writerow(item_values)
答案 0 :(得分:3)
首先要测量当前代码的时间性能:从输入中提取一个小的代表性数据样本,以便您可以在几秒钟(一分钟,顶部)运行基准测试。保存代码生成的输出,以测试您以后没有破坏任何内容。
首先我们需要更改字符串,因为我们使用JSON字典和 对于所有项目,数据都有类似的键(" track") - 如果我们不这样做的话 这个,输出只给出第一个轨道。
第二件事是避免更改字符串(删除代码的第一部分)。在最坏的情况下(如果您的900M文件实际上不是json文件,因为json格式不支持json对象中的重复名称:"When the names within an object are not
unique, the behavior of software that receives such an object is
unpredictable."),您可以使用类似multidict()
solution的内容大文件,例如,如果你使用python2然后避免创建一个不需要的列表的.items()
调用,你可以改用.iteritems()
,避免复制dict(d)
,只返回defaultdict
:< / p>
import json
from collections import defaultdict
def multidict(ordered_pairs):
"""Convert duplicate key values to a list."""
# read all values into list
d = defaultdict(list)
for k, v in ordered_pairs:
d[k].append(v)
# collapse list that has only 1 item
for k, v in d.iteritems():
if len(v) == 1:
d[k] = v[0]
return d
with open('filename.json') as json_file:
obj = json.load(json_file, object_pairs_hook=multidict)
每次更改后,再次测量时间性能并检查输出是否仍然正确。
为了便于阅读,您可以重写第二部分:
import csv
with open('output.csv', 'wb') as csv_file:
writer = csv.writer(csv_file)
for i, data in enumerate(data_d.itervalues(), start=1):
for item in data:
t = item['time']
writer.writerow([
#TRACK
i,
#DAY
t[8:10],
#COORDINATEN
item['tl']['x'],
item['tl']['y'],
item['br']['x'],
item['br']['y'],
#TIME
t[11:13]+t[14:16]+t[17:19]+t[20:23],
])
如果使用multidict()
代替字符串替换并未改善时间性能,那么您可以尝试滥用multidict()
来更改输入格式,而无需在内存中加载整个json对象: / p>
#!/usr/bin/env python2
import json
import sys
from collections import defaultdict
def write_tracks(ordered_pairs):
# read all values into list
d = defaultdict(list)
for k, v in ordered_pairs:
d[k].append(v)
# collapse list that has only 1 item
for k, v in d.iteritems():
if k == 'track':
for tracks in v: # print one track (in json format) per line
print("\n".join(map(json.dumps, tracks)))
break
elif len(v) == 1:
d[k] = v[0]
else: # no tracks, return the constructed object
return d
json.load(sys.stdin, object_pairs_hook=write_tracks) # write tracks
您可以从命令行中使用它:
$ <filename.json python write_tracks.py | python convert_tracks.py >output.csv
其中convert_tracks.py
类似于:
#!/usr/bin/env python2
import csv
import json
import sys
def main():
writer = csv.writer(sys.stdout)
for i, line in enumerate(sys.stdin, start=1):
try:
item = json.loads(line)
except ValueError:
pass # ignore errors
else:
t = item['time']
writer.writerow([
#TRACK
i,
#DAY
t[8:10],
#COORDINATEN
item['tl']['x'],
item['tl']['y'],
item['br']['x'],
item['br']['y'],
#TIME
t[11:13]+t[14:16]+t[17:19]+t[20:23],
])
if __name__ == "__main__":
main()
答案 1 :(得分:1)
在这一行中,有两件事情向我跳出来:
while ('track' in fil) :
首先 - 每次都会执行此while
循环。如果您仅仅因此而遇到性能问题,我不会感到惊讶。每次完成替换时,它都会再次搜索整个字符串。这真的很低效。
由于您只是使用文本对象而不是JSON对象,因此最好使用带有函数替换的正则表达式,或者使用其他基于正则表达式的策略,它会找到所有匹配项,然后您就可以使用它。像这样:
i = 0
def sub_track(g):
global i
i += 1
return "tr_%s" % i
RE_track = re.compile('track')
RE_track.sub(sub_track, data)
您也可以使用像sed
这样的非python程序,只需创建一个文件的副本,并替换掉所有出现的内容。
第二:我认为搜索“轨道”这个单词并不聪明。您可以匹配实际数据。我至少会尝试将其匹配为JSON密钥,并搜索/替换像"track":[
这样的字符串。
sed
在命令行上执行此操作,或尝试找出在数据块中执行此操作的方法并读取一行+逐行写入一行。我假设这是一行,所以你不能用readlines()迭代文件描述符,并且必须与字节范围有关。我以前从未处理过分析数据流的问题,因此无法对此提供任何见解。
答案 2 :(得分:0)
试试这样: -
import json
from pprint import pprint
json_data=open(filename.json)
data = json.load(json_data)
pprint(data)
json_data.close()