Tengo un DataFrame:

df = pd.DataFrame({
'keywords': [['a', 'b', 'c'], ['c', 'd'], ['a', 'b', 'c', 'd'], ['b', 'c', 'g', 'h', 'i']]})

Quiero contar el número de elementos en el DataFrame dentro de las listas en todas las filas usando df.apply. Espero que el DataFrame anterior dé:

a: 2
b: 3
c: 4
d: 2
g: 1
h: 1
i: 1
0
panaceanoob 16 oct. 2018 a las 14:18

2 respuestas

La mejor respuesta

Primero, tenga en cuenta que puede usar "sum" para concatenar listas, porque + concatena listas en Python:

df.keywords.sum()
# out: ['a', 'b', 'c', 'c', 'd', 'a', 'b', 'c', 'd', 'b', 'c', 'g', 'h', 'i']

Entonces tambien:

import collections
collections.Counter(df.keywords.sum())
# out: Counter({'a': 2, 'b': 3, 'c': 4, 'd': 2, 'g': 1, 'h': 1, 'i': 1})

O:

np.unique(df.keywords.sum(), return_counts=True)
# out: (array(['a', 'b', 'c', 'd', 'g', 'h', 'i'], dtype='<U1'),  array([2, 3, 4, 2, 1, 1, 1]))

O:

uniq = np.unique(df.keywords.sum(), return_counts=True)
pd.Series(uniq[1], uniq[0])
# out:
a    2
b    3
c    4
d    2
g    1
h    1
i    1

O:

pd.Series(collections.Counter(df.keywords.sum()))
# out: same as previous

En cuanto al rendimiento, es más o menos lo mismo si usa np.unique() o collections.Counter, porque df.keywords.sum() en realidad no es tan rápido. Si le importa el rendimiento, una lista pura de Python el aplanamiento es mucho más rápido:

collections.Counter([item for sublist in df.keywords for item in sublist])
2
John Zwinck 16 oct. 2018 a las 11:30

Puede usar la solución Python pura para aplanar con chain si el rendimiento es importante y contar los valores por Counter, el último uso del constructor DataFrame:

from itertools import chain
from collections import Counter

c = Counter(chain.from_iterable(df['keywords'].tolist())) 

df = pd.DataFrame({'a': list(c.keys()), 'b':list(c.values())})
print (df)
   a  b
0  a  2
1  b  3
2  c  4
3  d  2
4  g  1
5  h  1
6  i  1

O:

df = pd.DataFrame(df['keywords'].values.tolist()).stack().value_counts().to_frame('a')
print (df)
   a
c  4
b  3
a  2
d  2
g  1
i  1
h  1
1
jezrael 16 oct. 2018 a las 11:30