在pandas中,最有效的计数出现次数的方法是什么?

222

我有一个大的(约12M行)DataFramedf:

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数据框构建起来会花费很长时间。

4个回答

330

我认为应该使用df['word'].value_counts()。通过跳过groupby工具,您将节省一些时间。我不确定为什么countmax慢得多。两者都需要花费一些时间来避免缺失值。(与size进行比较。)

无论如何,value_counts已经被特别优化来处理对象类型,例如您的单词,因此我怀疑您不会比那更好。


37
谢谢。我也发现这个方法可以加快在系列中计算特定值的速度,例如 df.word.value_counts()['myword'] 的速度大约是 len(df[df.word == 'myword']) 的两倍。 - fantabolous
3
回答我自己的问题(理解了):.stack() 函数。 - Vaidøtas I.
2
@Newbielp,我做了这个: df[[i for i in column_names]].astype('str').stack().value_counts().sum() 这相当于将每个选定的列设置为字符串类型,将所有单独的列堆叠在一起,基本上形成一列,然后对该列进行value_counts()和sum()操作。 :) Stack非常有用,可能不是最明显的选择,但对我的用例非常有效 :) - Vaidøtas I.
2
补充@fantabolous的评论,如果列中可能存在零值,请使用.get()方法。在这种情况下,.get()将返回None,而使用括号方法将引发错误。 - elPastor
为了限制结果数量,例如只显示出现次数最高的前10个单词,请使用df['word'].value_counts().nlargest(10) - cristiandatum
显示剩余3条评论

34

当您想要计算pandas数据框中某一列类别数据的频率时,请使用以下代码:df['Column_Name'].value_counts()

-来源.


26

在之前的回答中,只是想补充一点。不要忘记在处理实际数据时可能会存在空值,因此使用选项dropna=False默认为True)也可以将其计入计数中。

例如:

>>> df['Embarked'].value_counts(dropna=False)
S      644
C      168
Q       77
NaN      2

3

统计出现次数的其他可能方法包括使用 (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为object,则非常大的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')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接