问题描述
我有一个包含多个帐户的数据框,其中显示了不同模式的动物类别。如何识别具有 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