[英]Python calculate co-occurrence of tuples in list of lists of tuples
我有很多元組列表,例如
actions = [ [('d', 'r'), ... ('c', 'e'),('', 'e')],
[('r', 'e'), ... ('c', 'e'),('d', 'r')],
... ,
[('a', 'b'), ... ('c', 'e'),('c', 'h')]
]
我想找到元組的同時出現。
我已經嘗試過從這個問題中得出結論,但是被接受的答案太慢了。 例如,在具有1494個元組列表的列表中,得到的字典大小為18225703,花了幾個小時才能運行2個元組共現。 因此,由於我的清單更大,所以簡單的排列和計數似乎不是答案。
我希望輸出會提取出最常見的對(2)或更多(最多3,4,5)元組。 以上一個列表為例:
('c', 'e'),('d', 'r')
在搜索對時會很常見,因為它們經常同時出現。 是否有一種有效的方法來實現這一目標?
我認為沒有希望有更快的算法:您必須計算組合來計算它們。 但是,如果您對共現閾值不感興趣,可以降低算法的復雜度。 在這兩種情況下,都希望減少空間復雜度。
讓我們舉一個小例子:
>>> actions = [[('d', 'r'), ('c', 'e'),('', 'e')],
... [('r', 'e'), ('c', 'e'),('d', 'r')],
... [('a', 'b'), ('c', 'e'),('c', 'h')]]
對於大量列表, 此答案可能是最好的,但是您可以避免創建中間列表。 首先,在所有現有的元素對上創建一個可迭代的元素(在您的情況下,元素也是對的,但這無關緊要):
>>> import itertools
>>> it = itertools.chain.from_iterable(itertools.combinations(pair_list, 2) for pair_list in actions)
如果要查看結果,則必須使用可迭代的:
>>> list(it)
[(('d', 'r'), ('c', 'e')), (('d', 'r'), ('', 'e')), (('c', 'e'), ('', 'e')), (('r', 'e'), ('c', 'e')), (('r', 'e'), ('d', 'r')), (('c', 'e'), ('d', 'r')), (('a', 'b'), ('c', 'e')), (('a', 'b'), ('c', 'h')), (('c', 'e'), ('c', 'h'))]
再算上排序對(用新鮮的it
!)
>>> it = itertools.chain.from_iterable(itertools.combinations(pair_list, 2) for pair_list in actions)
>>> from collections import Counter
>>> c = Counter((a,b) if a<=b else (b,a) for a,b in it)
>>> c
Counter({(('c', 'e'), ('d', 'r')): 2, (('', 'e'), ('d', 'r')): 1, (('', 'e'), ('c', 'e')): 1, (('c', 'e'), ('r', 'e')): 1, (('d', 'r'), ('r', 'e')): 1, (('a', 'b'), ('c', 'e')): 1, (('a', 'b'), ('c', 'h')): 1, (('c', 'e'), ('c', 'h')): 1})
>>> c.most_common(2)
[((('c', 'e'), ('d', 'r')), 2), ((('', 'e'), ('d', 'r')), 1)]
至少在空間方面,此解決方案應該是有效的,因為一切都是懶惰的,並且Counter
的元素數是同一列表中元素的組合數,即最多N(N-1)/2
,其中N
是所有列表中不同元素的數量(“最多”是因為某些元素從不“相遇”,因此不會發生任何組合)。
時間復雜度為O(M . L^2)
,其中M
是列表數, L
是最大列表的大小。
我假設列表中的所有元素都是不同的。 關鍵思想是, 如果一個元素僅出現在一個列表中,則該元素在此游戲中完全沒有機會擊敗任何人 :它將與所有鄰居共同出現1
,與其他列表中的元素同時出現0次。 如果有很多“孤兒”,則在處理組合時將其刪除可能會很有用:
>>> d = Counter(itertools.chain.from_iterable(actions))
>>> d
Counter({('c', 'e'): 3, ('d', 'r'): 2, ('', 'e'): 1, ('r', 'e'): 1, ('a', 'b'): 1, ('c', 'h'): 1})
>>> orphans = set(e for e, c in d.items() if c <= 1)
>>> orphans
{('a', 'b'), ('r', 'e'), ('c', 'h'), ('', 'e')}
現在,嘗試相同的算法:
>>> it = itertools.chain.from_iterable(itertools.combinations((p for p in pair_list if p not in orphans), 2) for pair_list in actions)
>>> c = Counter((a,b) if a<=b else (b,a) for a,b in it)
>>> c
Counter({(('c', 'e'), ('d', 'r')): 2})
注意理解:括號中沒有括號。
如果您在N個元素的列表中有K個孤兒,則該列表的時間復雜度將從N(N-1)/2
降至(NK)(NK-1)/2
,即(如果我沒有記錯! ) K.(2N-K-1)
組合較少。
這可以概括為:如果一個元素出現在兩個或更少的列表中,則該元素與其他元素最多同時出現2次,依此類推。
如果仍然很慢,請切換到較快的語言。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.