Python 中多个账户的多种模式

问题描述

我有一个包含多个帐户的数据框,其中显示了不同模式的动物类别。如何识别具有 1 种以上模式的帐户?

例如,注意账号 3 只有一种模式(即“狗”),但账号 1、2 和 4 有多种模式(即不止一种模式)。

test = pd.DataFrame({'account':[1,1,2,3,4,4],'category':['cat','dog','rabbit','cat','rabbit']})

我正在寻找的预期输出是这样的:

pd.DataFrame({'account':[1,'modes':[3,2]})

除此之外,我还尝试为具有多种模式的所有帐户采用任何随机最高模式。我想出了以下代码,但是,这仅返回每个帐户的第一个(字母顺序)模式。我的直觉告诉我可以在下面的 iloc 括号内写一些东西,也许是一个介于 0 和模式总数之间的随机数组,但我无法完全到达那里。

test.groupby('account')['category'].agg(lambda x: x.mode(dropna=False).iloc[0])

有什么建议吗?非常感谢。

解决方法

你可以使用 numpy.random.choice

targetID
,

不确定你想要什么,但你可以试试:

out=test.groupby('account')['category'].apply(lambda x: x.mode(dropna=False).values)

out 的输出:

account
1    [cat,dog,rabbit]
2            [cat,dog]
3                 [dog]
4         [cat,rabbit]
Name: category,dtype: object

对于随机模式值:

from random import choice

out=test.groupby('account')['category'].agg(
    lambda x: choice(x.mode(dropna=False)))

out 的输出(每次运行代码都会得到不同的输出):

account
1    rabbit
2       dog
3       dog
4    rabbit
Name: category,dtype: object

对于您预期的输出用途:

out=test.groupby('account')['category'].apply(lambda x: x.mode(dropna=False).count()).reset_index()
out=out[out['category'].ne(1)]

out 的输出:

account     category
0   1       3
1   2       2
3   4       2
,

因为您只想要任意随机模式,可以使用groupby + size。 (本质上是一个与 @abw333's solution 非常相似的包装器)。这很好,因为它避免了任何 groupby.apply 有利于内置的 groupby.size,它很快。

我们在 groupby 中使用 sort=False,因此结果系列按组在原始 DataFrame 中出现的顺序排序。然后,由于排序算法 'mergesort' 在平局的情况下是稳定的,因此在平局的情况下,这将确定性地返回出现在 DataFrame 中first(前一行)的模式。因此,如果您想获得 random 模式,您可以在应用它之前.sample(frac=1),以便它对所有行进行洗牌,然后返回该模式。

def fast_mode(df,gp_cols,value_col):
    """ 
    Calculate the mode of a column,ignoring null values recognized by pandas. 

    If there is a tie for the mode,the modal value is the modal value that appears **first** in the
    DataFrame. 

    Parameters
    ----------
    df : pandas.DataFrame
        DataFrame over which to calcualate the mode. 
    gp_cols : list of str
        Columns to groupby for calculation of mode.
    value_col : str
        Column for which to calculate the mode. 

    Return
    ------ 
    pandas.DataFrame
        One row for the modal value per key_cols 
    """

    return ((df.groupby(gp_cols + [value_col],observed=True,sort=False).size() 
               .to_frame('mode_counts').reset_index() 
               .sort_values('mode_counts',ascending=False,kind='mergesort') 
               .drop_duplicates(subset=gp_cols))
             .reset_index(drop=True))

# Will always return the same one that occurs first in DataFrame
fast_mode(df,gp_cols=['account'],value_col='category')
#   account category  mode_counts
#0        3      dog            3
#1        2      cat            2
#2        4   rabbit            2
#3        1      cat            1

# Sampling allows you to select a "random one" in case of ties
fast_mode(df.sample(frac=1,random_state=12),value_col='category')
#   account category  mode_counts
#0        3      dog            3
#1        4      cat            2
#2        2      dog            2
#3        1      cat            1