2017-01-21 12 views
5

Возможно, мне не хватает очевидного.Pandas: Используйте groupby для каждого элемента списка

У меня есть панд dataframe, который выглядит следующим образом:

id  product    categories 
    0  Silmarillion   ['Book', 'Fantasy'] 
    1  Headphones   ['Electronic', 'Material'] 
    2  Dune     ['Book', 'Sci-Fi'] 

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

Book  2 
Fantasy 1 
Electronic 1 
Material 1 
Sci-Fi  1 

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

+3

Помимо: панды не полностью поддерживает нескалярных записи в данный момент, и вы можете иногда получить таинственные сбои при их использовании. Обычно безопаснее перерабатывать ваш фрейм, чтобы каждая строка содержала только скалярные записи. – DSM

ответ

5

Вы можете нормализовать записи путем укладки их тогда называют value_counts():

pd.DataFrame(df['categories'].tolist()).stack().value_counts() 
Out: 
Book   2 
Fantasy  1 
Material  1 
Sci-Fi  1 
Electronic 1 
dtype: int64 
4

попробовать это:

In [58]: df['categories'].apply(pd.Series).stack().value_counts() 
Out[58]: 
Book   2 
Fantasy  1 
Electronic 1 
Sci-Fi  1 
Material  1 
dtype: int64 
+0

@ayhan, почему вы удалили свое решение? Думаю, это было лучше, чем у меня – MaxU

+0

Работает как шарм, спасибо! – Skum

+0

@MaxU '.apply (pd.Series)' казался более явным, чем 'pd.DataFrame (ser.tolist())'. Шахта выглядит как побочный эффект, который может не работать в будущем. – ayhan

5

Вы также можете позвонить pd.value_counts непосредственно в списке.
Вы можете создать соответствующий список с помощью numpy.concatenate, itertools.chain или cytoolz.concat

from cytoolz import concat 
from itertools import chain 

cytoolz.concat

pd.value_counts(list(concat(df.categories.values.tolist()))) 

itertools.chain

pd.value_counts(list(chain(*df.categories.values.tolist()))) 

numpy.unique + numpy.concatenate

u, c = np.unique(np.concatenate(df.categories.values), return_counts=True) 
pd.Series(c, u) 

Все выход

Book   2 
Electronic 1 
Fantasy  1 
Material  1 
Sci-Fi  1 
dtype: int64 

время тестирования

enter image description here

+1

ничего себе! это быстро! – MaxU

+1

Спасибо @NickilMaveli ... Я пропустил это ;-) – piRSquared

+0

Я получаю эту путаницу, возникающую ;-) –