【问题标题】:Determine if a Python list is 95% the same?确定一个 Python 列表是否 95% 相同?
【发布时间】:2011-04-26 20:24:33
【问题描述】:

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

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

【问题讨论】:

  • @Tim:找出哪个元素是预期的元素实际上有点棘手。
  • 嗯,预期的元素必然是分布的模式。没有其他值可以达到 95%。
  • 不确定计算完整分布是否满足效率要求。
  • 在第二个示例中,您如何获得 80% 的数字?我不明白你要计算什么。根据我的理解,第二个例子应该是 87.5% 相同。 (8 个中有 7 个)

标签: python algorithm list


【解决方案1】:
>>> 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

【讨论】:

  • Python 的后兜里确实隐藏着一些巧妙的技巧。
  • 应该注意这需要 Python 2.7 版本,这是 Counter 子类被添加到 collections 模块的时候。
  • @martineau:它被添加到 py3.1 然后向后移植到 2.7,也就是说它已经存在了一段时间。此外,Python 2.7 是 Python 的当前稳定版本。
  • @SilentGhost:我知道这一点,只是提出了依赖关系,因为出于各种原因,使用该网站的许多人没有或不能使用最新版本的 Python 2——并且有时不明白这就是为什么特定答案对他们不起作用的原因。
  • @martineau:你可以在 Python ≥2.5 中使用code.activestate.com/recipes/576611
【解决方案2】:

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

它也适用于您,只是最后您检查所选元素是否满足 95% 的阈值,而不是 50%。 (不过,正如 Thilo 所指出的,如果 currentCount &gt;= 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

【讨论】:

  • +1。在)。查看所有其他答案应该可以解决这个问题是否“微不足道”的争论。
  • 优秀的动画演示在这里:cs.utexas.edu/~moore/best-ideas/mjrty/index.html
  • 在此之后,您需要再次通过以确保多数确实是 95%(除了已经可以从 currentCount 的最终值推断出的情况)。
  • @larsmans 是的,没有完美的解决方案。 (我已经在帖子中提到,需要检查是否满足给定的频率速率。)您的算法也很好,尽管它使用了大量的额外内存并且可能会更慢。
  • @larsmans 我同意您的解决方案是一个很好的解决方案(没有花哨的定理和教科书算法,您可以获得最好的解决方案)。尽管如此,我确实认为对输入列表的第二次传递将比调用哈希 n 次更快。 (也就是说,假设输入列表完全可用)
【解决方案3】:
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 可以替换为单个循环。

【讨论】:

  • 可以将lambda: 0替换为int,保证初始化为0。
  • @Nikita Rybak 提出的 Boyer-Moore 算法有 O(N)
  • 虽然这是一个正确的解决方案,但我认为 Thilos 的早断解决方案更好。
【解决方案4】:

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

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

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

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

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

所以我认为您必须开始为表的前 5% 构建频率表。

【讨论】:

  • 我喜欢这个主意。这很容易理解,应该很快。棘手的部分是找出停止条件,但我认为这相当容易。
  • 忘记我的回答,使用 Nikita 概述的 Boyer-Moore 的多数投票算法。
【解决方案5】:
def ninety_five_same(l):
  return max([l.count(i) for i in set(l)])*20 >= 19*len(l)

也消除了浮点除法精度的问题。

【讨论】:

  • 否则很好,但你确实完整地计算了 plus set 生产的每个值的整个列表。很重的东西,列表很大,有很多不同的值,但总长度的一小部分。
【解决方案6】:

将您的清单想象成一桶红球和黑球。

如果你在一个有十个球的桶里有一个红球,你随机挑选一个球,把它放回桶里,然后重复这个采样和替换步骤一千次,总共有多少次平均而言,您预计有一千人会观察到一个红球?

查看Binomial 分发版并查看confidence intervals。如果您的清单很长,并且想要相对高效地做事,那么抽样是您的最佳选择。

【讨论】:

  • 问题是你不仅有红色和黑色的球(而且可能有数百种不同的颜色)。考虑到存在 O(N) 精确解,采样似乎非常不可靠。
  • 如果你知道颜色的数量,你总是可以扩展到多项式。例如,如果您的列表包含数十亿个或更长的元素,则采样几千个“球”可能比需要遍历列表中每个元素的 O(n) 方法更具吸引力。
  • 你怎么知道颜色的数量?
  • 如果您先验地知道什么样的球(“对象”)进入桶(“列表”),那么您可以适当地建模。
【解决方案7】:

作为通用解决方案的排序可能很重,但考虑到 Python 中 tim 排序的出色平衡性质,它利用了列表的现有顺序。我建议对列表进行排序(或排序后的副本,但该副本会损害性能)。从头到尾扫描找到相同的元素或达到扫描长度> 5 %,否则列表与找到的元素有95%相似。

将随机元素作为候选元素并按频率降序对它们进行计数可能也不会那么糟糕,直到找到的计数 > 95 % 或总计数超过 5%。

【讨论】:

    【解决方案8】:
    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 &gt;= 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-03-13
      • 1970-01-01
      • 1970-01-01
      • 2021-10-06
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多