我有一个pandas DataFrame,一列包含一个用管道分隔的字符串。这些来自电影流派。他们看起来像这样:
Genre
Adventure|Animation|Children|Comedy|Fantasy
Comedy|Romance
...
我使用str.split将它们作为列表返回到单元格中。像这样:
Genre
[Adventure, Animation, Children, Comedy, Fantasy]
[Adventure, Children, Fantasy]
[Comedy, Romance]
[Comedy, Drama, Romance]
[Comedy]
我想获得所有类型的总和。例如,喜剧出现了多少次? Adventure等做了多少次?我似乎无法弄清楚。
这看起来像
Comedy 4
Adventure 2
Animation 1
(...and so on...)
答案 0 :(得分:3)
我也赞成使用chain
+ for
。
只需对此进行记录,另一种可能的方法是使用get_dummies
df['Genre'].str.get_dummies(sep='|').sum()
答案 1 :(得分:2)
作为for循环俱乐部的人,我建议使用python的C加速例程-itertools.chain
和collections.Counter
-以提高性能。
from itertools import chain
from collections import Counter
pd.Series(
Counter(chain.from_iterable(x.split('|') for x in df.Genre)))
Adventure 1
Animation 1
Children 1
Comedy 2
Fantasy 1
Romance 1
dtype: int64
为什么我认为CPython函数比熊猫“矢量化”字符串函数更好?它们天生就难以向量化。您可以在For loops with pandas - When should I care?上阅读更多内容。
如果必须处理NaN,则可以调用一个可以正常处理异常的函数:
def try_split(x):
try:
return x.split('|')
except AttributeError:
return []
pd.Series(
Counter(chain.from_iterable(try_split(x) for x in df.Genre)))
通常,您可以使用split
,stack
和value_counts
来做到这一点。
df['Genre'].str.split('|', expand=True).stack().value_counts()
Comedy 2
Romance 1
Children 1
Animation 1
Fantasy 1
Adventure 1
dtype: int64
即使是很小的DataFrame,时间差异也很明显。
%timeit df['Genre'].str.get_dummies(sep='|').sum()
%timeit df['Genre'].str.split('|', expand=True).stack().value_counts()
%%timeit
pd.Series(
Counter(chain.from_iterable(try_split(x) for x in df.Genre)))
2.8 ms ± 68.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
2.4 ms ± 210 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
320 µs ± 9.71 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)