计算熊猫数量的最有效方法是什么?

我有一个大的(约12M行)数据帧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()

我哪里做错了?是否有更好的方法来计算大数据帧中出现的次数?

df.word.describe()

运行得很好,所以我真的没有料到这个Occurrences_of_Words数据帧需要很长时间来构建。

323829 次浏览

我认为df['word'].value_counts()应该适用。通过跳过机器分组,您将节省一些时间。我不确定为什么count应该比max慢得多。两者都需要一些时间来避免丢失值。(与size比较。)

在任何情况下,value_counts已经特别优化来处理对象类型,就像你的单词,所以我怀疑你能做得更好。

当你想要计算pandas dataFrame中一个列中分类数据的频率时,使用:df['Column_Name'].value_counts()

-

只是对之前答案的补充。不要忘记,在处理实际数据时,可能会有空值,因此通过使用选项dropna=False (默认值是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是最好的方法(尽管它仍然略优于其他方法,特别是对于非常大的Series)。

基准

(如果计数排序并不重要):

如果我们看一下运行时,它取决于存储在DataFrame列/Series中的数据。

如果Series是dtype对象,那么对于非常大的Series,最快的方法是collections.Counter,但通常value_counts非常具有竞争力。

enter image description here

然而,如果它是dtype int,那么最快的方法是numpy.unique:

enter image description here

用于生成图的代码:

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')