Groupby应用自定义功能熊猫

时间:2019-04-12 04:37:57

标签: python pandas dplyr

我正在尝试在熊猫中应用自定义功能,类似于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)

但是我想我仍然想知道是否存在一种无需定义此自定义函数的方法。

4 个答案:

答案 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

在 python 中很容易复制这个
>>> 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 软件包的作者。