簡體   English   中英

如何提高嵌套理解的性能?

[英]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.groupbycollections.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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM