Python:计算列表中元素对的频率

6
实际上,我有一个关于“会议”的数据集。 例如,A、B、C参加了一次会议,那么列表将为[A、B、C]。像这样,每个列表都包含参加会议的成员列表。 因此: line1=(A、B、C) line2=(A、C、D、E) line3=(D、F、G) ... 我只想计算每对成员彼此相遇的次数。 例如,成员A在line1和line2中与C相遇了两次,成员B在line1中与C相遇了一次。因此,我想制作如下图表。
    A  B  C  D E F G...

 A  .  1  2  1 ...  

 B  1  . 1  0 

 C

我一开始以为这很简单,但我感到非常困惑。 请帮帮我,非常感谢。


1
是时候学习如何矩阵相乘了... - Ignacio Vazquez-Abrams
3个回答

8

不要手动计算频率,使用collections.Counteritertools

from collections import Counter
from itertools import chain, combinations

meets = Counter(chain.from_iterable(combinations(line, 2) for line in lines))

其中lines是一组名称的可迭代对象。


使用Python库进行翻译,以下是翻译后的文本:一切都在那里,+1。>:P - Jungle Hunter
如果有一个解决方案是如此显而易见,以至于在看到你的答案之前我都没有注意到它,那么请给我点个赞。当其他答案使用defaultdict(int)并且经常执行d[item] += 1时,这似乎很适合使用Counter。更不用说问题本身就是“我想要计数...”了。 - lvc
1
请注意,这仅在每个列表中元素的顺序相同的情况下才有效,例如Counter(chain.from_iterable(combinations(x,2) for x in [[1,2],[2,1]]))会产生Counter({(1, 2): 1, (2, 1): 1})。如果您想计算每个配对而不考虑顺序,请先将每个列表转换为集合:Counter(chain.from_iterable(combinations(x,2) for x in [set([1,2]),set([2,1])]))会产生Counter({(1, 2): 2}) - Katrina

0

看起来你应该能够使用矩阵加法解决这个问题。如果你知道总人数(G),那么你的答案将会是一个GxG的矩阵。创建一个由line1组合而成的GxG矩阵,然后再添加一个由line2组合而成的GxG矩阵,以此类推。


0
这是一个相当简单的数据结构问题,可以使用2D数组或字典来解决。如果你有很多人,数组会更有效率,但我假设你没有那么多人。
times_met = defaultdict(int)
for line in lines:
     for pair in itertools.combinations(line, 2)
         times_met[pair] += 1

# How many times person a meets person b is described by the following (s.t. a < b)
print times_met[(a, b)]

请注意,如果您有大型会议并且可能存在更有效的算法,则此方法效率非常低下。

1
我认为一个元组到整数的字典会更有意义 - 这样 people_met[(person1, person2)] 就是他们之间的会议。然后它就不需要成为一个 defaultdict - 只需最初从 itertools.combinations 填充即可。 - lvc
@lvc 从语义上讲,defaultdict(int) 更有意义。如果新的人加入数据集,你可以询问他与其他任何人开会的次数,并得到正确的答案-0-而不是 KeyError。此外,用零初始化相当不符合 Python 的风格。你永远不需要一个 defaultdict,但它可以让你编写更好的代码。 - agf
修改很好,但是对于大型数据集来说仍然效率低下,因为你生成了线条与自身的笛卡尔积,而不是组合。请记住,Python是内置电池--已经有一种方法可以做到这一点。 - agf
是的,谢谢你的提示;我有点误解了第一条评论,认为最好使用它来替换defaultdict的初始化。这样做更好。 - phsource

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