我有一个python
脚本,它与以下内容有关:
pandas
数据框pandas
数据帧问题在于,每次迭代处理时间都在增加。 具体来说:
0-1000 documents -> 5 seconds
1000-2000 documents -> 6 seconds
2000-3000 documents -> 7 seconds
...
10000-11000 documents -> 18 seconds
11000-12000 documents -> 19 seconds
...
22000-23000 documents -> 39 seconds
23000-24000 documents -> 42 seconds
...
34000-35000 documents -> 69 seconds
35000-36000 documents -> 72 seconds
为什么会这样?
我的代码如下:
# 'documents' is the list of jsons
columns = ['column_1', 'column_2', ..., 'column_19', 'column_20']
df_documents = pd.DataFrame(columns=columns)
for index, document in enumerate(documents):
dict_document = dict.fromkeys(columns)
...
(parsing the jsons and retrieve the values of the keys and assign them to the dictionary)
...
df_documents = df_documents.append(dict_document, ignore_index=True)
PS
在应用@eumiro的建议后,以下时间如下:
0-1000 documents -> 0.06 seconds
1000-2000 documents -> 0.05 seconds
2000-3000 documents -> 0.05 seconds
...
10000-11000 documents -> 0.05 seconds
11000-12000 documents -> 0.05 seconds
...
22000-23000 documents -> 0.05 seconds
23000-24000 documents -> 0.05 seconds
...
34000-35000 documents -> 0.05 seconds
35000-36000 documents -> 0.05 seconds
在应用@DariuszKrynicki的建议后,以下时间如下:
0-1000 documents -> 0.56 seconds
1000-2000 documents -> 0.54 seconds
2000-3000 documents -> 0.53 seconds
...
10000-11000 documents -> 0.51 seconds
11000-12000 documents -> 0.51 seconds
...
22000-23000 documents -> 0.51 seconds
23000-24000 documents -> 0.51 seconds
...
34000-35000 documents -> 0.51 seconds
35000-36000 documents -> 0.51 seconds
...
答案 0 :(得分:7)
是的,append
在每行新行之后都将变慢,因为它必须一次又一次地复制整个(增长的)内容。
创建一个简单列表,将其追加到其中,然后一步创建一个DataFrame:
records = []
for index, document in enumerate(documents):
…
records.append(dict_document)
df_documents = pd.DataFrame.from_records(records)
答案 1 :(得分:2)
答案可能已经在您经常使用的pandas.DataFrame.append
方法中。这是非常低效的,因为它需要经常分配新的内存,即复制旧的内存,这可以解释您的结果。另请参见官方pandas.DataFrame.append docs:
将行迭代添加到DataFrame可能比单个连接更多地占用大量计算资源。更好的解决方案是将这些行添加到列表中,然后一次将列表与原始DataFrame连接起来。
带有两个示例:
效率较低:
>>> df = pd.DataFrame(columns=['A']) >>> for i in range(5): ... df = df.append({'A': i}, ignore_index=True) >>> df A 0 0 1 1 2 2 3 3 4 4
更高效:
>>> pd.concat([pd.DataFrame([i], columns=['A']) for i in range(5)], ... ignore_index=True) A 0 0 1 1 2 2 3 3 4 4
您可以应用相同的策略,创建数据框列表,而不是每次迭代都附加到相同的数据框,然后在concat
循环完成后for
答案 2 :(得分:1)
我怀疑您的DataFrame每次迭代都在增长。 如何使用迭代器?
# documents = # json
def get_df_from_json(document):
columns = ['column_1', 'column_2', ..., 'column_19', 'column_20']
# parsing the jsons and retrieve the values of the keys and assign them to the dictionary)
# dict_document = # use document to parse it and create dictionary
return pd.DataFrame(list(dict_document.values()), index=dict_document)
res = (get_df_from_json(document) for document in enumerate(documents))
res = pd.concat(res).reset_index()
编辑: 我在下面的示例中进行了快速比较,结果发现,使用迭代器并不能加快代码的列表理解速度:
import json
import time
def get_df_from_json():
dd = {'a': [1, 1], 'b': [2, 2]}
app_json = json.dumps(dd)
return pd.DataFrame(list(dd.values()), index=dd)
start = time.time()
res = pd.concat((get_df_from_json() for x in range(1,20000))).reset_index()
print(time.time() - start)
start = time.time()
res = pd.concat([get_df_from_json() for x in range(1,20000)]).reset_index()
print(time.time() - start)
迭代器:9.425999879837036 清单理解:8.934999942779541