更快的替代方法来执行pandas groupby操作

ast*_*ist 6 python numpy pandas pandas-groupby

我有一个名称(person_name),日期和颜色(shirt_color)作为列的数据集.

每个人在特定的日子穿着具有特定颜色的衬衫.天数可以是任意的.

例如输入:

name  day  color
----------------
John   1   White
John   2   White
John   3   Blue
John   4   Blue
John   5   White
Tom    2   White
Tom    3   Blue
Tom    4   Blue
Tom    5   Black
Jerry  1   Black
Jerry  2   Black
Jerry  4   Black
Jerry  5   White
Run Code Online (Sandbox Code Playgroud)

我需要找到每个人最常用的颜色.

例如结果:

name    color
-------------
Jerry   Black
John    White
Tom     Blue
Run Code Online (Sandbox Code Playgroud)

我正在执行以下操作来获得结果,这很好但很慢:

most_frquent_list = [[name, group.color.mode()[0]] 
                        for name, group in data.groupby('name')]
most_frquent_df = pd.DataFrame(most_frquent_list, columns=['name', 'color'])
Run Code Online (Sandbox Code Playgroud)

现在假设我有一个包含500万个唯一名称的数据集.执行上述操作的最佳/最快方式是什么?

piR*_*red 6

Numpy numpy.add.atpandas.factorize

这是为了快速.但是,我试图将它组织成可读的.

i, r = pd.factorize(df.name)
j, c = pd.factorize(df.color)
n, m = len(r), len(c)

b = np.zeros((n, m), dtype=np.int64)

np.add.at(b, (i, j), 1)
pd.Series(c[b.argmax(1)], r)

John     White
Tom       Blue
Jerry    Black
dtype: object
Run Code Online (Sandbox Code Playgroud)

groupby,sizeidxmax

df.groupby(['name', 'color']).size().unstack().idxmax(1)

name
Jerry    Black
John     White
Tom       Blue
dtype: object

name
Jerry    Black
John     White
Tom       Blue
Name: color, dtype: object
Run Code Online (Sandbox Code Playgroud)

Counter

¯\_(?)_/¯

from collections import Counter

df.groupby('name').color.apply(lambda c: Counter(c).most_common(1)[0][0])

name
Jerry    Black
John     White
Tom       Blue
Name: color, dtype: object
Run Code Online (Sandbox Code Playgroud)

  • 第1个:每个循环362 µs±1.47 µs(平均±标准偏差,共运行7次,每个循环1000个) (3认同)
  • 第二:每个循环 1.51 ms ± 4.67 µs(平均值 ± 标准偏差,7 次运行,每次 1000 次循环) (3认同)
  • 第三:834 µs ± 2.66 µs 每个循环(平均值 ± 标准偏差。7 次运行,每次 1000 次循环) (3认同)

DYZ*_*DYZ 5

更新

必须很难击败它(示例 daraframe 比任何提议的 Pandas 解决方案快 10 倍,比提议的 numpy 解决方案快 1.5 倍)。要点是远离熊猫并使用itertools.groupby它在涉及非数值数据时做得更好。

from itertools import groupby
from collections import Counter

pd.Series({x: Counter(z[-1] for z in y).most_common(1)[0][0] for x,y 
          in groupby(sorted(df.values.tolist()), 
                            key=lambda x: x[0])})
# Jerry    Black
# John     White
# Tom       Blue
Run Code Online (Sandbox Code Playgroud)

旧答案

这是另一种方法。它实际上比原来的慢,但我会保留在这里:

data.groupby('name')['color']\
    .apply(pd.Series.value_counts)\
    .unstack().idxmax(axis=1)
# name
# Jerry    Black
# John     White
# Tom       Blue
Run Code Online (Sandbox Code Playgroud)


WeN*_*Ben 5

解决方案来自 pd.Series.mode

df.groupby('name').color.apply(pd.Series.mode).reset_index(level=1,drop=True)
Out[281]: 
name
Jerry    Black
John     White
Tom       Blue
Name: color, dtype: object
Run Code Online (Sandbox Code Playgroud)