pandas:对dataframe进行groupby后求众数mode

1. 问题

有如下一个dataframe,打算对a的每一个类别求b的众数(mode),dir(df.groupby('a'))可以看到是没有mode函数的,因此不能直接使用df.groupby('a').mode().reset_index()

>>> import pandas as pd
>>> df = pd.DataFrame({'a':['A','A','A','A','B','B','B','B','B'],'b':[1,1,2,3,1,2,2,3,3]})
>>> df
   a  b
0  A  1
1  A  1
2  A  2
3  A  3
4  B  1
5  B  2
6  B  2
7  B  3
8  B  3

>>> df.groupby('a').mode().reset_index()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\site-packages\pandas\core\groupby.py", line 548, in __getattr__
    return self._make_wrapper(attr)
  File "C:\Python27\lib\site-packages\pandas\core\groupby.py", line 562, in _make_wrapper
    raise AttributeError(msg)
AttributeError: Cannot access callable attribute 'mode' of 'DataFrameGroupBy' objects, try using the 'apply' method

>>> type(df.groupby('a'))
<class 'pandas.core.groupby.DataFrameGroupBy'>
>>> dir(df.groupby('a'))
['__bytes__', '__class__', ... ... 'std', 'sum', 'tail', 'take', 'transform', 'tshift', 'var']

2. 解决方案

既然df.groupby('a')没有mode函数,又考虑到可能聚合函数agg能够接用外部函数,搜索网上的解决办法,经过尝试,在此总结并列出以下几种解决方案(当然也可以直接跳到最后一个解决方案)。

  1. 使用scipy.stats.mode():df中的B类别有两个众数,返回的结果B类别的众数取了较小的结果

    >>> from scipy import stats
    >>> df.groupby('a').agg(lambda x: stats.mode(x)[0][0]).reset_index()
       a  b
    0  A  1
    1  B  2
  2. 使用value_counts()
    (1) 先看value_counts()的作用:可以看到得到的结果中的index是取值,内容是计数,并且index是降序排列的,因此取index[0]是取最大值,因此有两个众数以上的时候,会取到较大的结果

    >>> ss = pd.Series([1,2,2,3,3])
    >>> ss
    0    1
    1    2
    2    2
    3    3
    4    3
    dtype: int64
    >>> ss.value_counts()
    3    2
    2    2
    1    1
    dtype: int64
    >>> ss.value_counts().index[0]
    3

    (2) 应用到dataframe的groupby之后的聚合函数中:

    >>> df.groupby('a').agg(lambda x: x.value_counts().index[0]).reset_index()
       a  b
    0  A  1
    1  B  3
  3. 使用pd.Series.mode():该函数是返回Series的众数的,当众数有多个时,会返回一个list,里面包含了所有众数

    >>> df.groupby('a').agg(pd.Series.mode).reset_index()
       a       b
    0  A       1
    1  B  [2, 3]
  4. 使用pd.Series.mode()np.mean():上述结果显然不是我想要的,但是如果对有多个众数的结果取均值作为新的众数,是较为满意的结果,则可以这样

    >>> import numpy as np
    >>> df.groupby('a').agg(lambda x: np.mean(pd.Series.mode(x))).reset_index()
      a    b
    0  A  1.0
    1  B  2.5
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值