[英]How can I improve performance of nested comprehension?
我正在嘗試使用 python 3.x comprehension 創建嵌套字典結構。 我的理解語法有效,但速度很慢,尤其是在大數據集的情況下。 我還使用循環創建了我想要的數據結構,它運行得更快,但我想知道是否有辦法改進這種理解,使其更有效,並且可能運行得與我的循環代碼一樣快,甚至更快。
我的輸入數據是一個字典列表,每個字典都概述了業余無線電聯系人的詳細信息(日志條目)。 這是我的數據的一個隨機子集(限制為 20 個條目,並刪除了字典中的非必要鍵以使其更清楚)
[{'BAND': '20M',
'CALL': 'AA9GL',
'COUNTRY': 'UNITED STATES OF AMERICA',
'QSO_DATE': '20170528',
'TIME_ON': '132100'},
{'BAND': '20M',
'CALL': 'KE4BFI',
'COUNTRY': 'UNITED STATES OF AMERICA',
'QSO_DATE': '20150704',
'TIME_ON': '034600'},
{'BAND': '20M',
'CALL': 'W8OTR',
'COUNTRY': 'UNITED STATES OF AMERICA',
'QSO_DATE': '20190119',
'TIME_ON': '194645'},
{'BAND': '10M',
'CALL': 'FY5FY',
'COUNTRY': 'FRENCH GUIANA',
'QSO_DATE': '20150328',
'TIME_ON': '161953'},
{'BAND': '17M',
'CALL': 'KD5FOY',
'COUNTRY': 'UNITED STATES OF AMERICA',
'QSO_DATE': '20190121',
'TIME_ON': '145630'},
{'BAND': '10M',
'CALL': 'K5GQ',
'COUNTRY': 'UNITED STATES OF AMERICA',
'QSO_DATE': '20150110',
'TIME_ON': '195326'},
{'BAND': '10M',
'CALL': 'CR5L',
'COUNTRY': 'PORTUGAL',
'QSO_DATE': '20151025',
'TIME_ON': '182351'},
{'BAND': '20M',
'CALL': 'AD4TR',
'COUNTRY': 'UNITED STATES OF AMERICA',
'QSO_DATE': '20170325',
'TIME_ON': '144606'},
{'BAND': '40M',
'CALL': 'EA8FJ',
'COUNTRY': 'CANARY ISLANDS',
'QSO_DATE': '20170618',
'TIME_ON': '020300'},
{'BAND': '10M',
'CALL': 'PY2DPM',
'COUNTRY': 'BRAZIL',
'QSO_DATE': '20150104',
'TIME_ON': '205900'},
{'BAND': '17M',
'CALL': 'MM0HVU',
'COUNTRY': 'SCOTLAND',
'QSO_DATE': '20170416',
'TIME_ON': '130200'},
{'BAND': '10M',
'CALL': 'LW3DG',
'COUNTRY': 'ARGENTINA',
'QSO_DATE': '20161029',
'TIME_ON': '210629'},
{'BAND': '10M',
'CALL': 'LW3DG',
'COUNTRY': 'ARGENTINA',
'QSO_DATE': '20151025',
'TIME_ON': '210714'},
{'BAND': '20M',
'CALL': 'EI7HDB',
'COUNTRY': 'IRELAND',
'QSO_DATE': '20170423',
'TIME_ON': '184000'},
{'BAND': '20M',
'CALL': 'KM0NAS',
'COUNTRY': 'UNITED STATES OF AMERICA',
'QSO_DATE': '20180102',
'TIME_ON': '142151'},
{'BAND': '10M',
'CALL': 'PY2TKB',
'COUNTRY': 'BRAZIL',
'QSO_DATE': '20150328',
'TIME_ON': '223535'},
{'BAND': '40M',
'CALL': 'EB1DJ',
'COUNTRY': 'SPAIN',
'QSO_DATE': '20170326',
'TIME_ON': '232430'},
{'BAND': '40M',
'CALL': 'LU6PCK',
'COUNTRY': 'ARGENTINA',
'QSO_DATE': '20150615',
'TIME_ON': '000200'},
{'BAND': '17M',
'CALL': 'G3RKF',
'COUNTRY': 'ENGLAND',
'QSO_DATE': '20190121',
'TIME_ON': '144315'},
{'BAND': '20M',
'CALL': 'UA1ZKI',
'COUNTRY': 'EUROPEAN RUSSIA',
'QSO_DATE': '20170508',
'TIME_ON': '141400'}]
我想創建一個字典,其中每個鍵都是一個頻段(10M、20M 等),值將是一個字典,列出該頻段上聯系的縣作為鍵,以及該頻段上每個國家/地區的聯系人計數作為值。 這是我的輸出:
{'10M': {'ARGENTINA': 2,
'BRAZIL': 2,
'FRENCH GUIANA': 1,
'PORTUGAL': 1,
'UNITED STATES OF AMERICA': 1},
'17M': {'ENGLAND': 1, 'SCOTLAND': 1, 'UNITED STATES OF AMERICA': 1},
'20M': {'EUROPEAN RUSSIA': 1, 'IRELAND': 1, 'UNITED STATES OF AMERICA': 5},
'40M': {'ARGENTINA': 1, 'CANARY ISLANDS': 1, 'SPAIN': 1}}
這是我為創建輸出而提出的理解。 它可以工作,並且在此處顯示的有限數據集下,它運行得很快,但是對於包含幾千個條目的輸入列表,它需要很長時間才能運行。
worked_dxcc_by_band = {
z["BAND"]: {
x["COUNTRY"]: len([y["COUNTRY"]
for y in log_entries
if y["COUNTRY"] == x["COUNTRY"] and y["BAND"] == z["BAND"]])
for x in log_entries
if x["BAND"] == z["BAND"]
}
for z in log_entries
}
因為這是一個三重嵌套的理解,並且所有 3 個循環都貫穿整個 log_entries 列表,所以我假設這就是它變得非常慢的原因。
有沒有更有效的方法來理解這一點? 我很好地使用我的循環來處理數據,但我正在努力提高我的理解能力,所以我認為這將是一個很好的練習!
這就是我在不使用理解的情況下所做的:我有一個函數 analyize_log_entry ,當我從文件中加載每個日志條目時,我會調用它。
from collections import Counter
worked_dxcc_by_band = {}
def analyze_log_entry(entry):
if "BAND" in entry:
if "COUNTRY" in entry:
if entry["BAND"] in worked_dxcc_by_band:
worked_dxcc_by_band[entry["BAND"]][entry["COUNTRY"]] += 1
else:
worked_dxcc_by_band[entry["BAND"]] = Counter()
worked_dxcc_by_band[entry["BAND"]][entry["COUNTRY"]] = 1
這本身可能不是那么有效,但我的完整代碼在構建多個字典的analyze_log_entry 函數中有許多類似的塊。 因為我只遍歷我的所有數據一次,並在適當的地方構建字典,所以它可能比使用理解更有效,理解本質上是多個循環。 正如我所說,這更像是一種學習如何使用不同方法完成相同任務的練習。
編輯:字典理解版本:
out = {band: dict(Counter(v['COUNTRY'] for v in g)) for band, g in groupby(sorted(data, key=lambda k: k['BAND']), lambda k: k['BAND'])}
您可以組合itertools.groupby
和collections.Counter
:
from itertools import groupby
from collections import Counter
s = sorted(data, key=lambda k: k['BAND'])
out = {}
for band, g in groupby(s, lambda k: k['BAND']):
c = Counter(v['COUNTRY'] for v in g)
out[band] = dict(c)
from pprint import pprint
pprint(out)
印刷:
{'10M': {'ARGENTINA': 2,
'BRAZIL': 2,
'FRENCH GUIANA': 1,
'PORTUGAL': 1,
'UNITED STATES OF AMERICA': 1},
'17M': {'ENGLAND': 1, 'SCOTLAND': 1, 'UNITED STATES OF AMERICA': 1},
'20M': {'EUROPEAN RUSSIA': 1, 'IRELAND': 1, 'UNITED STATES OF AMERICA': 5},
'40M': {'ARGENTINA': 1, 'CANARY ISLANDS': 1, 'SPAIN': 1}}
編輯:沒有模塊:
out = {}
for i in data:
out.setdefault(i['BAND'], {}).setdefault(i['COUNTRY'], 0)
out[i['BAND']][i['COUNTRY']] += 1
from pprint import pprint
pprint(out)
基准:
from timeit import timeit
from itertools import groupby
from collections import Counter
def sol_orig():
worked_dxcc_by_band = {z["BAND"]: {x["COUNTRY"] : len([y["COUNTRY"] for y in data if y["COUNTRY"] == x["COUNTRY"] and y["BAND"] == z["BAND"]]) for x in data if x["BAND"] == z["BAND"]} for z in data}
return worked_dxcc_by_band
def solution():
out = {band: dict(Counter(v['COUNTRY'] for v in g)) for band, g in groupby(sorted(data, key=lambda k: k['BAND']), lambda k: k['BAND'])}
return out
def solution_2():
out = {}
for i in data:
out.setdefault(i['BAND'], {}).setdefault(i['COUNTRY'], 0)
out[i['BAND']][i['COUNTRY']] += 1
return out
t1 = timeit(lambda: solution(), number=10000)
t2 = timeit(lambda: solution_2(), number=10000)
t3 = timeit(lambda: sol_orig(), number=10000)
print(t1)
print(t2)
print(t3)
印刷:
0.18113317096140236
0.08159565401729196
3.5367472909856588
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.