【问题标题】:Python co-occurrence of two items in different listsPython在不同列表中同时出现两个项目
【发布时间】:2017-02-16 11:12:53
【问题描述】:

我有一个列表,例如:

names =  [['cat', 'fish'], ['cat'], ['fish', 'dog', 'cat'],
 ['cat', 'bird', 'fish'], ['fish', 'bird']]

我想计算整个列表中每对名称一起提到的次数,输出如下:

{ ['cat', 'fish']: 3, ['cat', 'dog']: 1,['cat','bird']:1
 ['fish','dog'] : 1, ['fish','bird']:2} 

我试过了:

from collections import Counter
from collections import defaultdict

co_occurences = defaultdict(Counter)
for tags in names:
    for key in tags:
        co_occurences[key].update(tags)

print co_occurences

但它不计算主列表中的 co=occurrences。

【问题讨论】:

    标签: python list dictionary count find-occurrences


    【解决方案1】:

    来了。我使用<= 来测试一个集合是否是另一个集合的子集(集合没有顺序,每个元素只出现一次)。

    import itertools
    from pprint import pprint
    
    names = [['cat', 'fish'],
             ['cat'],
             ['fish', 'dog', 'cat'],
             ['cat', 'bird', 'fish'],
             ['fish', 'bird']]
    
    # Flatten the list and make all names unique
    unique_names = set(itertools.chain.from_iterable(names))
    
    # Get all combinations of pairs
    all_pairs = list(itertools.combinations(unique_names, 2))
    
    # Create the dictionary
    result = {pair: len([x for x in names if set(pair) <= set(x)]) for pair in all_pairs}
    
    pprint(result)
    

    这是输出

    {('bird', 'cat'): 1,
     ('bird', 'dog'): 0,
     ('bird', 'fish'): 2,
     ('dog', 'cat'): 1,
     ('fish', 'cat'): 3,
     ('fish', 'dog'): 1}
    

    我建议将它放在一个专用函数len([x for x in names if set(pair) &lt;= set(x)]) 中,用于字典的值。

    【讨论】:

    • 很好的答案!我建议在您的答案中使用专用函数,因为我认为它会使该部分代码更易于理解。我花了一段时间才弄清楚你为什么使用&lt;=,但一旦我明白了,我真的很喜欢它。
    • @SamMussmann 是的,会更新我的答案。我想补充一下,我确实提到过将其放入专用功能中! :-)
    【解决方案2】:

    您可以在 python 中使用按位与并通过将列表列表转换为集合列表来比较它们

    >>> set(['cat','dog']) & set(['cat','dog','monkey','horse','fish'])
    set(['dog', 'cat'])
    

    您可以使用此属性并达到您想要的计数。

    def listOccurences(item, names):
        # item is the list that you want to check, eg. ['cat','fish']
        # names contain the list of list you have.
        set_of_items = set(item) # set(['cat','fish'])
        count = 0
        for value in names:
            if set_of_items & set(value) == set_of_items:
                count+=1
        return count
    
    names =  [['cat', 'fish'], ['cat'], ['fish', 'dog', 'cat'],['cat', 'bird', 'fish'], ['fish', 'bird']]
    # Now for each of your possibilities which you can generate
    # Chain flattens the list, set removes duplicates, and combinations generates all possible pairs.
    permuted_values = list(itertools.combinations(set(itertools.chain.from_iterable(names)), 2))
    d = {}
    for v in permuted_values:
        d[str(v)] = listOccurences(v, names)
    # The key in the dict being a list cannot be possible unless it's converted to a string.
    print(d)
    # {"['fish', 'dog']": 1, "['cat', 'dog']": 1, "['cat', 'fish']": 3, "['cat', 'bird']": 1, "['fish', 'bird']": 2}
    

    【讨论】:

    • 我认为以编程方式创建permuted_values 会更好。考虑使用itertools.chain,就像 Elmex80s 的回答一样。
    • Sam Mussmann,完全同意,但这里的目的不是解决排列问题,而是显示计数方式,我假设当 OP 询问结果必须如何看待排列部分时已经解决了。但是是的,使用 itertools 链接和创建唯一的 2 对绝对是可能的并且推荐。如果您可以对答案进行编辑,那就太好了。
    【解决方案3】:

    您可以通过使用itertools.combinationsitertools.chain 来使用所需的结果:

    >>> from itertools import combinations, chain
    
    >>> names =  [['cat', 'fish'], ['cat'], ['fish', 'dog', 'cat'],
    ...  ['cat', 'bird', 'fish'], ['fish', 'bird']]
    >>> uniques = set(chain(*names))
    >>> {x: sum(1 for n in names if all(i in n for i in x))  for x in combinations(uniques, 2)}
    {('fish', 'dog'): 1, ('dog', 'cat'): 1, ('bird', 'fish'): 2, ('fish', 'cat'): 3, ('bird', 'dog'): 0, ('bird', 'cat'): 1}
    

    【讨论】:

      【解决方案4】:

      首先计算所有 2 个单词的组合,如果两个词出现在列表项中,则增加其在 result 字典中的值:(l 是整个列表中不同元素的列表):

      from collections import defaultdict
      from itertools import combinations, chain
      
      
      names =  [['cat', 'fish'], ['cat'], ['fish', 'dog', 'cat'],
       ['cat', 'bird', 'fish'], ['fish', 'bird']]
      l = set(chain.from_iterable(names)) # {'dog', 'bird', 'cat', 'fish'}
      result = defaultdict(int)
      for x in (list(combinations(l, 2))):
          for y in names:
              if((x[0] in y) and (x[1] in y)):
                  result[x[0],x[1]] += 1
      
      
      result # defaultdict(<class 'int'>, {('fish', 'bird'): 2, ('cat', 'dog'): 1, ('cat', 'fish'): 3, ('fish', 'dog'): 1, ('cat', 'bird'): 1})
      

      【讨论】:

        【解决方案5】:

        此处列出的解决方案不适用于我的大型数据集(成千上万),它们太慢了。以下解决方案速度更快,只需几分之一秒。

        在此处查看 Counter 类

        https://docs.python.org/2/library/collections.html#collections.Counter

        # generate combinations for each sub list seperately
        lists_of_pairs = [list(itertools.combinations(sub_list, 2)) for sub_list in names]
        # flatten the lists of pairs to 1 large list of pairs
        all_pairs = [pair for pairs_list in lists_of_pairs for pair in pairs_list]
        # let the Counter do the rest for you
        co_occurences_counts = Counter(all_pairs)
        

        【讨论】:

        • 如果我想考虑像 ['cat','cat'] 这样的情况怎么办?同名成对。
        猜你喜欢
        • 2020-07-10
        • 2021-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-31
        相关资源
        最近更新 更多