我有一个大(大约 12M 行)DataFrame df
:
df.columns = ['word','documents','frequency']
以下内容及时运行:
word_grouping = df[['word','frequency']].groupby('word')
MaxFrequency_perWord = word_grouping[['frequency']].max().reset_index()
MaxFrequency_perWord.columns = ['word','MaxFrequency']
但是,这需要很长时间才能运行:
Occurrences_of_Words = word_grouping[['word']].count().reset_index()
我在这里做错了什么?有没有更好的方法来计算大型 DataFrame 中的出现次数?
df.word.describe()
运行得很好,所以我真的没想到这个 Occurrences_of_Words
DataFrame 需要很长时间才能构建。
我认为 df['word'].value_counts()
应该发球。通过跳过 groupby 机制,您将节省一些时间。我不确定为什么 count
应该比 max
慢得多。两者都需要一些时间来避免缺失值。 (与 size
比较。)
在任何情况下, value_counts 一直是 specifically optimized 来处理对象类型,就像你的话,所以我怀疑你会做得比这更好。
只是对先前答案的补充。我们不要忘记,在处理真实数据时可能会有空值,因此使用选项 dropna=False
(default is True
) 将这些值也包括在计数中很有用
一个例子:
>>> df['Embarked'].value_counts(dropna=False)
S 644
C 168
Q 77
NaN 2
计算出现次数的其他可能方法是使用 (i) collections
模块中的 Counter
,(ii) numpy
库中的 unique
和 (iii) pandas
中的 groupby
+ size
。
要使用 collections.Counter
:
from collections import Counter
out = pd.Series(Counter(df['word']))
要使用 numpy.unique
:
import numpy as np
i, c = np.unique(df['word'], return_counts = True)
out = pd.Series(c, index = i)
要使用 groupby
+ size
:
out = pd.Series(df.index, index=df['word']).groupby(level=0).size()
上述方法中缺少的 value_counts
的一个非常好的特性是它对计数进行排序。如果对计数进行排序是绝对必要的,那么考虑到它的简单性和性能,value_counts
是最好的方法(即使它仍然略微优于其他方法,尤其是对于非常大的系列)。
基准
(如果对计数进行排序并不重要):
如果我们查看运行时,它取决于存储在 DataFrame 列/系列中的数据。
如果 Series 是 dtype 对象,那么对于非常大的 Series,最快的方法是 collections.Counter
,但一般来说 value_counts
是非常有竞争力的。
https://i.stack.imgur.com/bmd1Z.png
但是,如果是 dtype int,那么最快的方法是 numpy.unique
:
https://i.stack.imgur.com/ZHLKR.png
用于生成绘图的代码:
import perfplot
import numpy as np
import pandas as pd
from collections import Counter
def creator(n, dt='obj'):
s = pd.Series(np.random.randint(2*n, size=n))
return s.astype(str) if dt=='obj' else s
def plot_perfplot(datatype):
perfplot.show(
setup = lambda n: creator(n, datatype),
kernels = [lambda s: s.value_counts(),
lambda s: pd.Series(Counter(s)),
lambda s: pd.Series((ic := np.unique(s, return_counts=True))[1], index = ic[0]),
lambda s: pd.Series(s.index, index=s).groupby(level=0).size()
],
labels = ['value_counts', 'Counter', 'np_unique', 'groupby_size'],
n_range = [2 ** k for k in range(5, 25)],
equality_check = lambda *x: (d:= pd.concat(x, axis=1)).eq(d[0], axis=0).all().all(),
xlabel = '~len(s)',
title = f'dtype {datatype}'
)
plot_perfplot('obj')
plot_perfplot('int')
df.word.value_counts()['myword']
的速度大约是len(df[df.word == 'myword'])
的两倍。.get()
方法。在这种情况下,.get()
将返回None
,而使用括号方法将引发错误。