繁体   English   中英

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

[英]Determine if a Python list is 95% the same?

这个问题询问如何确定列表中的每个元素是否相同。 我如何以合理有效的方式确定列表中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

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

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

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

它也适用于你,最后你只检查所选元素是否满足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已经得到了最好的解释。

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 << 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可以用单个循环代替。

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

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

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

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

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

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

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

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

把你的名单想象成一桶红色和黑色的球。

如果你在一个十个球的桶中有一个红球,你随机挑选一个球并将其放回桶中,然后重复一次采样和替换步骤,一千次中有多少次你希望平均观察到一个红球?

查看二项分布并检查置信区间 如果你有一个很长的清单,并希望相对有效地做事,那么采样就是最佳选择。

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

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

将随机元素作为候选元素并通过降低频率顺序来计算它们可能也不会那么糟糕,直到发现计数> 95%或总计数超过5%。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM