【问题标题】:Finding mode of a list列表的查找模式
【发布时间】:2019-11-29 16:49:31
【问题描述】:

我正在编写一个函数来计算一个或多个数字列表的模式。

如果输入为[52, 99, 37, 86, 99, 99, 99, 37, 37, 37],则输出应为[37, 99]。正如您所看到的,应该先出现较小的数字,但我的代码不会这样做。有人可以修复我的代码吗?

def mode(L):
    most = max(list(map(L.count, L)))
    return list(set(filter(lambda x: L.count(x) == most, L)))

【问题讨论】:

  • 但是 set 是无序的。为什么你认为结果应该是有序的?
  • 您正在丢失订单。试试list(set(["b", "a"])) 看看吧。
  • 使用Counter.most_common,这样会更有效率
  • @Alex 我收到了['b', 'a'] 回复。我认为顺序取决于实现。
  • 万一将来有人用谷歌搜索这个,一旦 Python 3.8 出来,答案就变成了import statistics; sorted(statistics.multimode(L))

标签: python


【解决方案1】:

sorted() 对您的列表进行排序。

def mode(L):
    most = max(list(map(L.count, L)))
    return sorted(list(set(filter(lambda x: L.count(x) == most, L))))

更新
注意:这是一种非常低效的计算模式。其他答案中有更多高性能的解决方案。这个答案只关注OP的要求。请勿在生产中使用此代码。
另请参阅 cmets 中有关此代码的其他改进的注释。

【讨论】:

  • 你可以在两条线上去掉list()。他们没有为你做任何事情。 max() 将使用 map() 迭代器,sorted() 将愉快地使用 set
  • 请注意,它的性能糟糕。考虑在 10 项列表上执行 list(map(L.count, L)) L.count() 被调用 10 次,并且必须迭代超过 10 项才能进行计数。这是 10 个项目的 100 (10*10) 次访问。 10:1。但是,如果列表有 100 个项目,则它的访问量为 10,000 (100*100)。 1000:1。因此,通过将列表增长 10 倍,迭代的成本增长了 100 倍。这就是二次增长。在我的电脑上,一旦 L 变成 10,000 个项目,它就会变得非常缓慢,而其他答案仍然快速进行。
  • @StevenRumbalski 我同意您的两位 cmets -- MatthewLee 您可能要同时考虑两者。然而,我的回答集中在 MatthewLee 所问的具体问题上。我现在在我的回答中为未来的读者添加了一条注释。
【解决方案2】:

另一种解决方案是使用collections.Counter

from collections import Counter

nums = [52, 99, 37, 86, 99, 99, 99, 37, 37, 37]

c = Counter(nums)
highest_freq = max(c.values())
mod = [n for n, freq in sorted(c.items()) if freq == highest_freq]

print(mod)

输出:

[37, 99]

如果你只需要一个项目,你也可以使用:

nums = [52, 99, 37, 86, 99, 99, 99, 37, 37, 37]
c = Counter(nums)
print(max(c))

哪个打印:

99

【讨论】:

  • Counter.most_common() 返回从最高到最低计数的项目迭代器。
  • 是的,但是你需要指定你想要多少。选择最常见的(不管有多少)需要手动迭代。
  • 不。请参阅@WillemVanOnsem 的回答。我独立(而且更慢)想出了同样的想法。
  • 仍然,groupby 遍历列表。我的意思是没有过滤就没有直接的解决方案。
  • 没有。 groupby 创建一个迭代器。它不进行迭代。当 next() 被调用时,它会迭代并调用项目上的 key 函数,直到迭代器的 key 函数的返回值发生变化(或迭代器耗尽)。所以这里为了创建第一个两个分组,它使用.most_common() 的前三个项目。因为第三个项目的计数不同,它将前两个项目分组并将它们作为一个组返回。 .most_common() 返回的迭代器没有进一步迭代。
【解决方案3】:

你在这里使它在计算上相当昂贵。 .count(..) 需要线性时间,使得这个算法是二次的。

您可以在这里使用Counter 对列表执行单次遍历,然后获取最常见的元素,例如:

from collections import Counter
from operator import itemgetter
from itertools import groupby

def mode(L):
    _, common = next(groupby(Counter(L).most_common(), itemgetter(1)))
    return sorted(map(itemgetter(0), common))

鉴于列表中的元素可以有效地散列,这将在线性时间内运行。

【讨论】:

  • 万一将来有人用谷歌搜索这个,一旦 Python 3.8 出来,答案就变成了import statistics; sorted(statistics.multimode(L))
猜你喜欢
  • 2012-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-28
相关资源
最近更新 更多