我正在尝试在熊猫中应用自定义功能,类似于dplyr中的groupby和mutate功能。
我想做的就是给这样一个熊猫数据框:
df = pd.DataFrame({'category1':['a','a','a', 'b', 'b','b'],
'category2':['a', 'b', 'a', 'b', 'a', 'b'],
'var1':np.random.randint(0,100,6),
'var2':np.random.randint(0,100,6)}
)
df
category1 category2 var1 var2
0 a a 23 59
1 a b 54 20
2 a a 48 62
3 b b 45 76
4 b a 60 26
5 b b 13 70
应用某些函数,该函数返回的元素数与分组依据中的元素数相同:
def myfunc(s):
return [np.mean(s)] * len(s)
获得此结果
df
category1 category2 var1 var2 var3
0 a a 23 59 35.5
1 a b 54 20 54
2 a a 48 62 35.5
3 b b 45 76 29
4 b a 60 26 60
5 b b 13 70 29
我在想一些类似的事情:
df['var3'] = df.groupby(['category1', 'category2'], group_keys=False).apply(lambda x: myfunc(x.var1))
但无法获取匹配的索引。
在dplyr中,R应该是
df <- df %>%
group_by(category1, category2) %>%
mutate(
var3 = myfunc(var1)
)
因此,我能够使用以下自定义函数来解决该问题:
def myfunc_data(data):
data['var3'] = myfunc(data.var1)
return data
和
df = df.groupby(['category1', 'category2']).apply(myfunc_data)
但是我想我仍然想知道是否存在一种无需定义此自定义函数的方法。
答案 0 :(得分:2)
尝试以下解决方案:
df.loc[:,'var3'] = df.groupby(['category1', 'category2']).var1.transform(myfunc)
答案 1 :(得分:2)
使用GroupBy.transform
返回Series
,其sime大小类似于原始DataFrame
,因此可以分配给新列:
np.random.seed(123)
df = pd.DataFrame({'category1':['a','a','a', 'b', 'b','b'],
'category2':['a', 'b', 'a', 'b', 'a', 'b'],
'var1':np.random.randint(0,100,6),
'var2':np.random.randint(0,100,6)}
)
df['var3'] = df.groupby(['category1', 'category2'])['var1'].transform(myfunc)
print (df)
category1 category2 var1 var2 var3
0 a a 66 86 82
1 a b 92 97 92
2 a a 98 96 82
3 b b 17 47 37
4 b a 83 73 83
5 b b 57 32 37
替代lambda function
:
df['var3'] = (df.groupby(['category1', 'category2'])['var1']
.transform(lambda s: [np.mean(s)] * len(s)))
答案 2 :(得分:1)
您可以使用apply
从技术上实现这一点,为完整性起见,我将在此处添加它,但是我建议使用transform
方法-它更简单,更快捷。
您遇到的问题是,您返回了多个值,这些值在使用apply
时会为您提供每一行的列表。相反,当您添加新列时,您可以只返回一个值并依靠pandas
明智地匹配这些值(并在必要时进行复制)。但是,要使此工作有效,我们需要具有与groupby / apply返回的系列相同的索引。这是您的操作方法(也请注意对myfunc
的修改):
import pandas as pd
def myfunc(s):
return np.mean(s)
df = pd.DataFrame({'category1':['a','a','a', 'b', 'b','b'],
'category2':['a', 'b', 'a', 'b', 'a', 'b'],
'var1':np.random.randint(0,100,6),
'var2':np.random.randint(0,100,6)}
)
df = (df.set_index(["category1", "category2"])
.assign(var3=df.groupby(["category1", "category2"]).var1.apply(myfunc))
.reset_index()
)
df
答案 3 :(得分:0)
使用 datar
>>> from datar.all import tibble, sample, mean
>>> from pipda import register_func
>>>
>>> df = tibble(
... category1=['a','a','a', 'b', 'b','b'],
... category2=['a', 'b', 'a', 'b', 'a', 'b'],
... # var1=sample(100, 6),
... # var2=sample(100, 6)
... var1=[23, 54, 48, 45, 60, 13],
... var2=[59, 20, 62, 76, 26, 70]
... )
>>> df
category1 category2 var1 var2
<object> <object> <int64> <int64>
0 a a 23 59
1 a b 54 20
2 a a 48 62
3 b b 45 76
4 b a 60 26
5 b b 13 70
>>>
>>> @register_func(None)
>>> def myfunc(s):
... return mean(s)
>>>
>>> df >> group_by(
... f.category1, f.category2
... ) >> mutate(
... var3 = myfunc(f.var1)
... )
category1 category2 var1 var2 var3
<object> <object> <int64> <int64> <float64>
0 a a 23 59 35.5
1 a b 54 20 54.0
2 a a 48 62 35.5
3 b b 45 76 29.0
4 b a 60 26 60.0
5 b b 13 70 29.0
[Groups: category1, category2 (n=4)]
免责声明:我是 datar
软件包的作者。