簡體   English   中英

從一堆清單中選擇最常見的元素

[英]Picking the most common element from a bunch of lists

我有長度相等的列表[l1, ..., ln]的列表l

我想比較len(l1)所有kl1[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] 如果有平局,我將查看構成平局的列表,並在列表中選擇優先級更高的一個。 優先級被賦予優先級,每個列表被賦予優先級。 例如 如果您在列表l1l3具有值1,在列表l2l4值2,並且在l5具有值3,並且列表是根據優先級排序的,例如l5>l2>l3>l1>l4 ,那么我將選擇2,因為2在l2中包含出現次數最高的元素,並且其優先級高於l1l3

如何在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.

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