2017-01-21 31 views
5

Może brakuje mi tego, co oczywiste.Pandy: Użyj groupby na każdym elemencie listy

Mam dataframe pandy, który wygląda tak:

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

Chciałbym użyć funkcji GroupBy policzyć liczbę wystąpień każdego elementu w kolumnie kategorii, więc o wynik byłby

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

jednak gdy próbuję przy użyciu funkcji GroupBy, pandy zlicza wystąpienia całej listy zamiast oddzielania jej elementów. Próbowałem różnych sposobów obsługi tego, używając krotek lub podziałów, ale do tej pory nie udało mi się.

+3

marginesie: pandy nie obsługuje w pełni nieskalarnych wpisy w tym momencie, a czasami można dostać tajemnicze awarie podczas korzystania z nich. Zwykle bezpieczniej jest przerobić ramkę tak, aby każdy wiersz zawierał tylko wpisy skalarne. – DSM

Odpowiedz

5

można znormalizować rekordy układając je następnie wywołać 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

spróbuj tego:

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, dlaczego usunąłeś swoje rozwiązanie? Domyślam się, że to było lepsze niż moje – MaxU

+0

Działa jak urok, dzięki! – Skum

+0

@MaxU '.apply (pd.Series)' wydawało się bardziej wyraźne niż 'pd.DataFrame (ser.tolist())'. Mój wygląda jak efekt uboczny, który może nie działać w przyszłości. – ayhan

5

Można również zadzwonić pd.value_counts bezpośrednio na liście.
Można wygenerować odpowiednią listę poprzez numpy.concatenate, itertools.chain lub 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) 

Wszystkie otrzymując

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

czas testowania

enter image description here

+1

wow! to jest szybkie! – MaxU

+1

Dziękuję @NickilMaveli ... Tęskniłem za tym ;-) – piRSquared

+0

Dostaję ten zamęt powstający ;-) –