Python pandas 相当于 R 的 group_by、mutate 和 ifelse

Kje*_*kås 9 python r pandas

可能是重复的,但我花了太多时间在这上面,现在谷歌搜索却没有任何运气。假设我有一个数据框:

import pandas as pd
data = {"letters": ["a", "a", "a", "b", "b", "b"],
        "boolean": [True, True, True, True, True, False],
        "numbers": [1, 2, 3, 1, 2, 3]}
df = pd.DataFrame(data)
df
Run Code Online (Sandbox Code Playgroud)

我想 1)按字母分组,2)如果布尔值中的所有值都具有相同的值,则取数字的平均值。在 RI 中会写:

library(dplyr)
df %>% 
  group_by(letters) %>%
  mutate(
    condition = n_distinct(boolean) == 1,
    numbers = ifelse(condition, mean(numbers), numbers)
  ) %>% 
  select(-condition)
Run Code Online (Sandbox Code Playgroud)

这将产生以下输出:

# A tibble: 6 x 3
# Groups:   letters [2]
  letters boolean numbers
  <chr>   <lgl>     <dbl>
1 a       TRUE          2
2 a       TRUE          2
3 a       TRUE          2
4 b       TRUE          1
5 b       TRUE          2
6 b       FALSE         3
Run Code Online (Sandbox Code Playgroud)

你会如何使用 Python pandas 来做到这一点?

Qua*_*ang 8

我们可以使用惰性groupby和transform:

g = df.groupby('letters')

df.loc[g['boolean'].transform('all'), 'numbers'] = g['numbers'].transform('mean')
Run Code Online (Sandbox Code Playgroud)

输出:

  letters  boolean  numbers
0       a     True        2
1       a     True        2
2       a     True        2
3       b     True        1
4       b     True        2
5       b    False        3
Run Code Online (Sandbox Code Playgroud)


wwn*_*nde 6

另一种方法是使用 np.where。当一组具有唯一值时,求均值。它不保留数字的地方。代码如下

df['numbers'] =np.where(df.groupby('letters')['boolean'].transform('nunique')==1,df.groupby('letters')['numbers'].transform('mean'), df['numbers'])



letters  boolean  numbers
0       a     True      2.0
1       a     True      2.0
2       a     True      2.0
3       b     True      1.0
4       b     True      2.0
5       b    False      3.0
Run Code Online (Sandbox Code Playgroud)

或者,在计算平均值时屏蔽条件不适用的情况。

m=df.groupby('letters')['boolean'].transform('nunique')==1

df.loc[m, 'numbers']=df[m].groupby('letters')['numbers'].transform('mean')
Run Code Online (Sandbox Code Playgroud)


Ony*_*mbu 5

由于您直接与 R 进行比较,我更愿意使用siuba而不是pandas:

from siuba import mutate, if_else, _, select, group_by, ungroup

df1 = df >>\
    group_by(_.letters) >> \
    mutate( condition = _.boolean.unique().size == 1, 
            numbers = if_else(_.condition, _.numbers.mean(), _.numbers)
          ) >>\
    ungroup() >> select(-_.condition)

print(df1)
letters  boolean  numbers
0       a     True      2.0
1       a     True      2.0
2       a     True      2.0
3       b     True      1.0
4       b     True      2.0
5       b    False      3.0
Run Code Online (Sandbox Code Playgroud)

注意那>>是管道。我添加\是为了跳到下一行。另请注意,要引用您使用的变量_.variable

编辑

看来你的 R 代码有问题,在 R 中,你应该使用condition = all(boolean)而不是你拥有的代码。这将翻译成condition = boolean.all()Python