确定Python列表是否相同95%?

时间:2010-10-18 09:24:34

标签: python algorithm list

This question询问如何确定列表中的每个元素是否相同。我如何以合理有效的方式确定列表中95%的元素是否相同?例如:

>>> ninety_five_same([1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1])
True
>>> ninety_five_same([1,1,1,1,1,1,2,1]) # only 80% the same
False

这需要有点效率,因为列表可能非常大。

8 个答案:

答案 0 :(得分:16)

>>> from collections import Counter
>>> lst = [1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
>>> _, freq = Counter(lst).most_common(1)[0]
>>> len(lst)*.95 <= freq
True

答案 1 :(得分:15)

实际上,对于类似的问题,有一个简单的线性解决方案,只有50%的约束而不是95%。 Check this question,它只是几行代码。

它也适用于你,最后你只检查所选元素是否满足95%的阈值,而不是50%。 (虽然,如 Thilo 所述,如果已经currentCount >= n*0.95,则没有必要。)

我还会从 st0le 的回答中发布Python代码,向大家展示它有多难。

currentCount = 0
currentValue = lst[0]
for val in lst:
   if val == currentValue:
      currentCount += 1
   else:
      currentCount -= 1

   if currentCount == 0:
      currentValue = val
      currentCount = 1

如果您正在寻找解释,我认为 Nabb 已获得the best one

答案 2 :(得分:6)

def ninety_five_same(lst):
    freq = collections.defaultdict(int)
    for x in lst:
        freq[x] += 1
    freqsort = sorted(freq.itervalues())
    return freqsort[-1] >= .95 * sum(freqsort)

假设完美的哈希表性能和良好的排序算法,这在O( n + m lg m )中运行,其中 m 是不同项目的数量。 O( n lg n )最坏的情况。

编辑:这是一个O( n + m ),单遍版本(假设 m &lt; ;&lt; n ):

def ninety_five_same(lst):
    freq = collections.defaultdict(int)
    for x in lst:
        freq[x] += 1
    freq = freq.values()
    return max(freq) >= .95 * sum(freq)

内存使用是O( m )。 maxsum可以替换为单个循环。

答案 3 :(得分:3)

这比检查每个元素是否相同效率更低。

算法大致相同,遍历列表中的每个元素并计算那些与预期的元素不匹配的元素(更难以知道哪一个是预期的元素)。但是,这次,当你遇到第一个不匹配时,你不能只返回false,你必须继续,直到你有足够的不匹配来弥补5%的错误率。

想一想,找出哪个元素是“正确的”可能并不那么容易,并且要计算每个值,直到可以确定5%是错位的。

考虑一个包含10.000个元素的列表,其中99%是42:

  (1,2,3,4,5,6,7,8,9,10, ... , 100, 42,42, 42, 42 .... 42)

所以我认为你必须开始至少为表格的前5%建立一个频率表。

答案 4 :(得分:1)

def ninety_five_same(l):
  return max([l.count(i) for i in set(l)])*20 >= 19*len(l)

同时消除浮动分割精度的问题。

答案 5 :(得分:0)

将您的列表视为一桶红色和黑色的球。

如果你在一个十个球的桶中有一个红球,你随机挑选一个球并将其放回桶中,然后重复该样品和更换步骤一千次,多少次,你平均会想要观察一个红球吗?

查看Binomial发布内容并查看confidence intervals。如果你有一个很长的清单,并希望相对有效地做事,那么采样就是最佳选择。

答案 6 :(得分:0)

lst = [1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
#lst = [1, 2, 1, 4, 1]
#lst = [1, 2, 1, 4]

length = len(lst)
currentValue = lst[0]
lst.pop(0)
currentCount = 1

for val in lst:
   if currentCount == 0:
      currentValue = val

   if val == currentValue:
      currentCount += 1
   else:
      currentCount -= 1

percent = (currentCount * 50.0 / length + 50)
epsilon = 0.1
if (percent - 50 > epsilon):
    print "Percent %g%%" % percent
else:
    print "No majority"

注意:epsilon有一个“随机”值,根据数组的长度选择一些东西等。 Nikita Rybak的currentCount >= n*0.95解决方案不起作用,因为currentCount的值因元素的顺序而异,但上面的确有效

C:\Temp>a.py
[2, 1, 1, 4, 1]
currentCount = 1

C:\Temp>a.py
[1, 2, 1, 4, 1]
currentCount = 2

答案 7 :(得分:0)

排序作为一般解决方案可能很重,但考虑Python中tim排序的非常均衡的性质,它利用列表的现有顺序。我建议对列表进行排序(或者使用已排序的副本,但该副本会损害性能)。从端部和前部扫描以找到相同的元件或达到扫描长度&gt; 5%,否则列表与找到的元素的95%相似。

将随机元素作为候选者并通过降低频率顺序对它们进行计数也不会那么糟糕,直到找到计数&gt; 95%或总计数超过5%。