从一堆列表中挑选最常见的元素

时间:2016-03-22 21:08:26

标签: python

我有一份长度等于[l1, ..., ln]的列表l

我想比较l1[k], l2[k], ..., ln[k]中所有k的{​​{1}},并通过选择最常出现的元素来制作另一个列表len(l1)

所以,如果是l0l1 = [1, 2, 3]l2 = [1, 4, 4],那么l3 = [0, 2, 4]。如果存在平局,我将查看构成平局的列表,并选择列表中具有更高优先级的列表。优先权是先验的,每个清单都有优先权。 防爆。如果您在列表l = [1, 2, 4]l1中有值1,在列表l3l2中有值2,在l4中有3,并且列表是根据优先级,比如说l5,然后我会选择2,因为2位于l5>l2>l3>l1>l4,其中包含一个出现次数最多的元素,其优先级高于l2l1

如何在没有创建包含大量if / else条件的for循环的情况下在python中执行此操作?

6 个答案:

答案 0 :(得分:4)

您可以使用集合库中的Counter模块。使用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语句!

答案 1 :(得分:3)

只需转置子列表并从每个组中获取Counter.most_common元素键:

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)])

如果他们是个人名单,只需输入:

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]

不确定如果存在平局,如何从分组中获取第一个元素是有意义的,因为它可能不是那个并列但实现起来很简单的元素,只需获取两个最常见的并检查它们的计数是否相等:< / p>

if len(comm) == 1

我们还需要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 ,以防所有元素都相同或者我们会得到一个IndexError。

如果你正在谈论在并列事件中采用来自早期列表的元素,即l5在l5之前,那么这与采用任何相关的元素相同。

对于相当数量的子列表:

{{1}}

答案 2 :(得分:2)

解决方案是:

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)]

答案 3 :(得分:2)

这就是你要找的东西:

from collections import Counter
from operator import itemgetter

l0 = [max(Counter(li).items(), key=itemgetter(1))[0] for li in zip(*l)]

答案 4 :(得分:2)

如果你可以选择最常见的一组元素中的任何一个,并且你可以保证你不会在列表列表中找到一个空列表,那么这是一种使用{{1 (所以,Counter):

from collections import Counter

在IPython中执行此操作并打印结果:

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])

答案 5 :(得分:1)

试试这个:

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)]