2014-11-07 5 views
1

У меня есть два массива одинакового размера тегов и категорий тегов. Я хочу группировать теги по категориям и подсчитывать теги.Подсчет событий в массивах numpy

Как вы можете видеть, теги могут делиться одними и теми же категориями («мир», «привет»).

Я знаю, что это можно легко сделать с помощью циклов, но я уверен, что у numpy есть несколько отличных способов сделать это более эффективно. Любая помощь будет принята с благодарностью.

# Tag category 
A = [10, 10, 20, 10, 10, 10, 20, 10, 20, 20] 
# Tags 
B = ['hello', 'world', 'how', 'are', 'you', 'world', 'you', 'how', 'hello', 'hello'] 

Ожидаемый результат:

[(10, (('hello', 1), ('are', 1), ('you', 1), ('world', 2))), (20, (('how', 1), ('you', 1), ('hello', 2)))] 
+0

[Pandas] (http://pandas.pydata.org/) может быть более подходящим для этого. –

ответ

2

Вы можете использовать вложенную collections.defaultdict для этого.

Здесь мы будем использовать целые числа от A в качестве ключа внешнего dict и для каждого внутреннего dict мы будем использовать слова из B как ключа, и их значение будет их счетчиком.

>>> from collections import defaultdict 
>>> from pprint import pprint 
>>> d = defaultdict(lambda: defaultdict(int)) 
>>> for k, v in zip(A, B): 
     d[k][v] += 1 

Теперь d содержит (я преобразовал его в нормальный Словаре, потому что его выход менее запутанным):

>>> pprint({k: dict(v) for k, v in d.items()}) 
{10: {'are': 1, 'hello': 1, 'how': 1, 'world': 2, 'you': 1}, 
20: {'hello': 2, 'how': 1, 'you': 1}} 

Теперь нам нужно перебрать внешней Dict и вызвать tuple(.iteritems()) на внешнем списке получить желаемый результат:

>>> pprint([(k, tuple(v.iteritems())) for k, v in d.items()]) 
[(10, (('world', 2), ('you', 1), ('hello', 1), ('how', 1), ('are', 1))), 
(20, (('how', 1), ('you', 1), ('hello', 2)))] 
+0

Я не следую этой части 'defaultdict (lambda: defaultdict (int))' вы можете объяснить более подробно. благодаря! –

+0

@marcin_koss Создает вложенную структуру словаря, где внешние ключи будут иметь словарь как значение, а внутренний словарь будет иметь целочисленное значение (по умолчанию 0). –

+0

Получил, спасибо. Теперь, что было бы лучшим способом также упорядочить тегов с помощью count? –

0

Вот один из способов:

>>> from collections import Counter 
>>> A = np.array([10, 10, 20, 10, 10, 10, 20, 10, 20, 20]) 
>>> B = np.array(['hello', 'world', 'how', 'are', 'you', 'world', 'you', 'how', 'hello','hello']) 
>>> [(i,Counter(B[np.where(A==i)]).items()) for i in set(A)] 
[(10, [('world', 2), ('you', 1), ('hello', 1), ('how', 1), ('are', 1)]), (20, [('how', 1), ('you', 1), ('hello', 2)])] 
+0

Это не будет масштабироваться так, как вы делаете это в квадратичное время. –

2

Поскольку это упомянуто, вот способ объединения значений с помощью Pandas.

Настройка DataFrame ...

>>> import pandas as pd 
>>> df = pd.DataFrame({'A': A, 'B': B}) 
>>> df 
    A  B 
0 10 hello 
1 10 world 
2 20 how 
3 10 are 
4 10 you 
5 10 world 
6 20 you 
7 10 how 
8 20 hello 
9 20 hello 

Поворотная агрегировать значений ...

>>> table = pd.pivot_table(df, rows='B', cols='A', aggfunc='size') 
>>> table 
A  10 20 
B    
are  1 NaN 
hello 1 2 
how  1 1 
world 2 NaN 
you  1 1 

Преобразование обратно в словарь ...

>>> table.to_dict() 
{10: {'are': 1.0, 'hello': 1.0, 'how': 1.0, 'world': 2.0, 'you': 1.0}, 
20: {'are': nan, 'hello': 2.0, 'how': 1.0, 'world': nan, 'you': 1.0}} 

Отсюда может использовать Python для настройки словаря в желаемый формат (например, список).

0

, но я уверен, что NumPy имеет некоторые изящные способы сделать это более эффективно

и вы правы! Вот код

# convert to integer 
category_lookup, categories = numpy.unique(A, return_inverse=True) 
tag_lookup, tags = numpy.unique(B, return_inverse=True) 

statistics = numpy.zeros([len(category_lookup), len(tag_lookup)]) 
numpy.add.at(statistics, [categories, tags], 1) 

result = {} 
for category, stat in zip(category_lookup, statistics): 
    result[category] = dict(zip(tag_lookup[stat != 0], stat[stat != 0])) 

Для пояснения см numpy tips and tricks. Это дает ожидаемый ответ:

{10: { 'являются': 1,0 'привет': 1,0 'как': 1,0 'мир': 2,0 'вы': 1.0}, 20: { 'hello': 2.0, 'how': 1.0, 'you': 1.0}}

Я признаю, что это не самый ясный способ сделать это (см. Решение pandas), но это очень быстро, когда у вас есть огромное количество данных.

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