Python 中多个帐户的多种模式
Multiple modes for multiple accounts in Python
我有一个包含多个帐户的数据框,这些帐户显示不同模式的动物类别。如何识别拥有不止一种模式的帐户?
例如,注意账号3只有一种模式(即“狗”),但账号1、2、4有多种模式(即不止一种模式)。
test = pd.DataFrame({'account':[1,1,1,2,2,2,2,3,3,3,3,4,4,4,4],
'category':['cat','dog','rabbit','cat','cat','dog','dog','dog','dog','dog','rabbit','rabbit','cat','cat','rabbit']})
我正在寻找的预期输出是这样的:
pd.DataFrame({'account':[1,2,4],'modes':[3,2,2]})
除此之外,我还尝试为所有具有多种模式的帐户采用任何随机最高模式。我想出了以下代码,但是,这只是 returns 每个帐户的第一个(字母顺序)模式。我的直觉告诉我可以在下面的 iloc
括号内写一些东西,也许是一个介于 0 和模式总数之间的随机数组,但我无法完全到达那里。
test.groupby('account')['category'].agg(lambda x: x.mode(dropna=False).iloc[0])
有什么建议吗?非常感谢。
你可以使用 numpy.random.choice
test.groupby('account')['category'].agg(
lambda x: np.random.choice(x.mode(dropna=False)))
不确定你想要什么,但你可以试试:
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
,因此生成的Series按照组在原始DataFrame中出现的顺序排序。然后因为排序算法 'mergesort'
在关系的情况下是稳定的,这将确定性地 return 在 DataFrame 中出现 first (较早的行)的模式关系的情况。因此,如果您想获得 随机 模式,您可以 .sample(frac=1)
在应用此模式之前,以便它随机播放所有行,然后 returns 模式。
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), gp_cols=['account'], value_col='category')
# account category mode_counts
#0 3 dog 3
#1 4 cat 2
#2 2 dog 2
#3 1 cat 1
我有一个包含多个帐户的数据框,这些帐户显示不同模式的动物类别。如何识别拥有不止一种模式的帐户?
例如,注意账号3只有一种模式(即“狗”),但账号1、2、4有多种模式(即不止一种模式)。
test = pd.DataFrame({'account':[1,1,1,2,2,2,2,3,3,3,3,4,4,4,4],
'category':['cat','dog','rabbit','cat','cat','dog','dog','dog','dog','dog','rabbit','rabbit','cat','cat','rabbit']})
我正在寻找的预期输出是这样的:
pd.DataFrame({'account':[1,2,4],'modes':[3,2,2]})
除此之外,我还尝试为所有具有多种模式的帐户采用任何随机最高模式。我想出了以下代码,但是,这只是 returns 每个帐户的第一个(字母顺序)模式。我的直觉告诉我可以在下面的 iloc
括号内写一些东西,也许是一个介于 0 和模式总数之间的随机数组,但我无法完全到达那里。
test.groupby('account')['category'].agg(lambda x: x.mode(dropna=False).iloc[0])
有什么建议吗?非常感谢。
你可以使用 numpy.random.choice
test.groupby('account')['category'].agg(
lambda x: np.random.choice(x.mode(dropna=False)))
不确定你想要什么,但你可以试试:
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
,因此生成的Series按照组在原始DataFrame中出现的顺序排序。然后因为排序算法 'mergesort'
在关系的情况下是稳定的,这将确定性地 return 在 DataFrame 中出现 first (较早的行)的模式关系的情况。因此,如果您想获得 随机 模式,您可以 .sample(frac=1)
在应用此模式之前,以便它随机播放所有行,然后 returns 模式。
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), gp_cols=['account'], value_col='category')
# account category mode_counts
#0 3 dog 3
#1 4 cat 2
#2 2 dog 2
#3 1 cat 1