在一个变长元组列表中找到出现最频繁的元素

3

我正在编写一段代码,用于从csv文件中返回公交线路中最常见的公交站牌编号。每行“bus_routes.csv”的第一个条目是路线名称,其余条目是公交站号码。

def most_common_number(routes):
    routes = load_routes('bus_routes.csv')
    bus_stop_ID = [col[1:] for col in routes]
    return max(sum(set((bus_stop_ID, []), key = sum(bus_stop_ID, []).count)

当我运行这段代码时,它会返回一个错误; TypeError:只能将列表(而不是“元组”)连接到列表 type(bus_stop_number) 是一个列表,所以我找不到在我上次的代码中存在元组的位置。

你可能需要使用collections.Countermost_common来代替你的代码,因为你的代码看起来非常复杂。但我们没有你的数据。一个小样本比我们没有的csv文件要好得多。 - Jean-François Fabre
你有多少列? col[1:] 可能会返回一个元组。分别打印并验证。然后像 Jean 所说的那样使用 collections.Counter。 - Sharan
1
这显然不是你的实际代码;set函数不接受key参数(或任何关键字参数),而且括号不匹配。 - Karl Knechtel
1个回答

4
我找不到元组在我上一个代码中的存在位置。 bus_stop_ID 的每个元素都是元组。
回顾一下,您有一个变长元组列表,并希望找到整个结构中最常见的元素。
这听起来像是一个完美的使用 collections.Counter 的案例:
>>> from collections import Counter
>>> bus_stop_ID = [('id1', 'id2', 'id3'), ('id1',), ('id1', 'id3', 'id5')]
>>> [(stop_id, count)] = sum(map(Counter, bus_stop_ID), Counter()).most_common(1)
>>> stop_id
'id1'
>>> count
3

这里:

  • map(Counter, bus_stop_ID) 将每条路线的车站ID进行单独计数;
  • sum(..., Counter()) 在所有路线中汇总计数;
  • .most_common(1) 返回计数最多的车站ID(作为一个包含两个元素的二元组列表,其中第一个元素是车站ID,第二个元素是它的计数)。

另一种方法是先使用sum()将所有路线连接起来,然后再进行计数:

>>> [(stop_id, count)] = Counter(sum(bus_stop_ID, ())).most_common(1)

这种方法较为简短,但效率较低,因为它需要将所有路由连接成一个(潜在的巨大)元组。

一种略显花哨的方法是通过使用 itertools.chain() 来规避这种低效性:

>>> Counter(itertools.chain(*bus_stop_ID)).most_common(1)
[('id1', 3)]

这只是简单地迭代第一路线中的所有公交站点ID,然后是第二个路线,以此类推,在此过程中进行计数。

出于好奇,我在一个任意选择的包含1万个元组的列表上测试了这三种方法,结果非常有趣:

In [11]: %timeit sum(map(Counter, bus_stop_ID), Counter()).most_common(1)
1 loop, best of 3: 235 ms per loop

In [12]: %timeit Counter(sum(bus_stop_ID, ())).most_common(1)
1 loop, best of 3: 2.64 s per loop

In [13]: %timeit Counter(itertools.chain(*bus_stop_ID)).most_common(1)
10 loops, best of 3: 17.3 ms per loop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接