2017-02-16 15 views
0

у меня есть список списков, таких как:Python смежности двух предметов в разных списках

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 

, но это не считается со = вхождения в основном список.

ответ

1

Вы можете использовать побитовое и в питона и сравнить их с помощью преобразования списка списков в список наборов

>>> 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} 
+0

Было бы лучше создать 'перестановочные_значения' программно, я думаю. Подумайте об использовании 'itertools.chain', как и ответ Elmex80s. –

+0

Сэм Муссманн, полностью согласен, но намерение здесь состояло в том, чтобы не решить проблему с перестановкой, чтобы показать способ подсчета, я предполагаю, что, когда ОП спросил, как результат должен был выглядеть, часть перестановки уже решена. Но да, используя itertools для цепочки и создания уникальных пар 2, безусловно, возможно и рекомендуется. было бы здорово, если бы вы могли отредактировать ответ. –

2

Вот оно. Я использую <=, чтобы проверить, является ли набор подмножеством другого набора (множества не имеют порядка, и каждый элемент появляется ровно один раз).

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) <= set(x)]) для значений словаря.

+0

Великий ответ! Я бы предложил использовать специальную функцию в вашем ответе, так как я думаю, что это сделает часть кода более понятной. Мне потребовалось некоторое время, чтобы понять, почему вы использовали '<=', но как только я понял, мне это очень понравилось. –

+0

@SamMussmann Да, верно, обновит мой ответ. Я хотел бы добавить, что я упомянул, чтобы поместить его в специальную функцию! :-) – Elmex80s

1

Сначала вычислим все 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}) 
1

Вы можете использовать желаемое результат через использование itertools.combinations и itertools.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} 
0

Решения, перечисленные здесь, не работает для моего большого набора данных (10s тысяч), они были слишком медленными. Следующее решение работает быстрее, оно занимает долю секунды.

Проверить класс Счетчик здесь

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) 

 Смежные вопросы

  • Нет связанных вопросов^_^