[英]Picking the most common element from a bunch of lists
我有長度相等的列表[l1, ..., ln]
的列表l
我想比較len(l1)
所有k
的l1[k], l2[k], ..., ln[k]
,並通過選擇出現頻率最高的元素制作另一個列表l0
。
因此,如果l1 = [1, 2, 3]
, l2 = [1, 4, 4]
l3 = [0, 2, 4]
l2 = [1, 4, 4]
和l3 = [0, 2, 4]
,則l = [1, 2, 4]
。 如果有平局,我將查看構成平局的列表,並在列表中選擇優先級更高的一個。 優先級被賦予優先級,每個列表被賦予優先級。 例如 如果您在列表l1
和l3
具有值1,在列表l2
和l4
值2,並且在l5
具有值3,並且列表是根據優先級排序的,例如l5>l2>l3>l1>l4
,那么我將選擇2,因為2在l2
中包含出現次數最高的元素,並且其優先級高於l1
和l3
。
如何在python中執行此操作而不創建帶有很多if / else條件的for循環?
您可以使用集合庫中的“計數器”模塊。 使用map
功能將減少列表循環。 對於沒有最頻繁值的情況,您僅需要一個if / else語句:
import collections
list0 = []
list_length = len(your_lists[0])
for k in list_length:
k_vals = map(lambda x: x[k], your_lists) #collect all values at k pos
counts = collections.Counter(k_vals).most_common() #tuples (val,ct) sorted by count
if counts[0][1] > counts[1][1]: #is there a most common value
list0.append(counts[0][0]) #takes the value with highest count
else:
list0.append(k_vals[0]) #takes element from first list
list0
是您正在尋找的答案。 我只是討厭使用l
因為它很容易與數字1
混淆
編輯 (基於評論):
合並您的注釋,而不是if / else語句,請使用while循環:
i = list_length
while counts[0][1] == counts[1][1]:
counts = collections.Counter(k_vals[:i]).most_common() #ignore the lowest priority element
i -= 1 #go back farther if there's still a tie
list0.append(counts[0][0]) #takes the value with highest count once there's no tie
所以整個事情就變成了:
import collections
list0 = []
list_length = len(your_lists[0])
for k in list_length:
k_vals = map(lambda x: x[k], your_lists) #collect all values at k pos
counts = collections.Counter(k_vals).most_common() #tuples (val,ct) sorted by count
i = list_length
while counts[0][1] == counts[1][1]: #in case of a tie
counts = collections.Counter(k_vals[:i]).most_common() #ignore the lowest priority element
i -= 1 #go back farther if there's still a tie
list0.append(counts[0][0]) #takes the value with highest count
您又拋出了一個小循環,但好的一面是根本沒有if / else語句!
只需轉置子列表並從每個組中獲取Counter.most_common
元素鍵:
from collections import Counter
lists = [[1, 2, 3],[1, 4, 4],[0, 2, 4]]
print([Counter(sub).most_common(1)[0][0] for sub in zip(*lists)])
如果它們是單獨的列表,請壓縮它們:
l1, l2, l3 = [1, 2, 3], [1, 4, 4], [0, 2, 4]
print([Counter(sub).most_common(1)[0][0] for sub in zip(l1,l2,l3)])
不確定如果有平局,從分組中取出第一個元素是有道理的,因為它可能不是平局的,但是實現起來很簡單,只需獲取兩個most_common並檢查它們的計數是否相等:
def most_cm(lists):
for sub in zip(*lists):
# get two most frequent
comm = Counter(sub).most_common(2)
# if their values are equal just return the ele from l1
yield comm[0][0] if len(comm) == 1 or comm[0][1] != comm[1][1] else sub[0]
if len(comm) == 1
所有元素都相同,我們還需要if len(comm) == 1
,否則我們將得到IndexError。
如果您要討論的是在出現平局時采用來自較早列表的元素,即l2在l5之前,則與采用任何平局的元素相同。
對於相當數量的子列表:
In [61]: lis = [[randint(1,10000) for _ in range(10)] for _ in range(100000)]
In [62]: list(most_cm(lis))
Out[62]: [5856, 9104, 1245, 4304, 829, 8214, 9496, 9182, 8233, 7482]
In [63]: timeit list(most_cm(lis))
1 loops, best of 3: 249 ms per loop
解決方法是:
a = [1, 2, 3]
b = [1, 4, 4]
c = [0, 2, 4]
print [max(set(element), key=element.count) for element in zip(a, b, c)]
這就是您要尋找的:
from collections import Counter
from operator import itemgetter
l0 = [max(Counter(li).items(), key=itemgetter(1))[0] for li in zip(*l)]
如果您可以接受最常見的一組元素中的任何一個,並且可以保證不會在列表列表中打空列表,那么可以使用Counter
(因此, from collections import Counter
):
l = [ [1, 0, 2, 3, 4, 7, 8],
[2, 0, 2, 1, 0, 7, 1],
[2, 0, 1, 4, 0, 1, 8]]
res = []
for k in range(len(l[0])):
res.append(Counter(lst[k] for lst in l).most_common()[0][0])
在IPython中執行此操作並打印結果:
In [86]: res
Out[86]: [2, 0, 2, 1, 0, 7, 8]
嘗試這個:
l1 = [1,2,3]
l2 = [1,4,4]
l3 = [0,2,4]
lists = [l1, l2, l3]
print [max(set(x), key=x.count) for x in zip(*lists)]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.