【问题标题】:Python pandas equivalent to R's group_by, mutate, and ifelsePython pandas 相当于 R 的 group_by、mutate 和 ifelse
【发布时间】:2022-01-18 03:52:53
【问题描述】:

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

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

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

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

这将导致以下输出:

# 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

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

【问题讨论】:

  • SO 并不是一个代码翻译服务。除了你的研究,你还尝试过什么?

标签: python r pandas


【解决方案1】:

我们可以使用懒惰的groupbytransform

g = df.groupby('letters')

df.loc[g['boolean'].transform('all'), 'numbers'] = g['numbers'].transform('mean')

输出:

  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

【讨论】:

    【解决方案2】:

    另一种方法是使用 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
    

    或者,在计算均值时屏蔽条件不适用的地方。

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

    【讨论】:

    • transform('all') 可以在这里重复使用;我觉得 nunique 可能很棘手,特别是如果所有布尔值都是 False
    【解决方案3】:

    由于您直接与 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
    

    注意&gt;&gt; 是管道。我添加了\ 以便跳转到下一行。另请注意,要引用您使用的变量_.variable

    编辑

    您的 R 代码似乎有问题,在 R 中,您应该使用 condition = all(boolean) 而不是您拥有的代码。这将在 Python 中转换为 condition = boolean.all()

    【讨论】:

      【解决方案4】:

      datar 是您的另一种解决方案:

      >>> 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)
      >>>
      >>> from datar.all import f, group_by, mutation, n_distinct, if_else, mean, select
      >>> df >> group_by(f.letters) \
      ...    >> mutate(
      ...         condition=n_distinct(f.boolean) == 1, 
      ...         numbers = if_else(f.condition, mean(f.numbers), f.numbers)
      ...       ) \
      ...    >> select(~f.condition)
         letters  boolean   numbers
        <object>   <bool> <float64>
      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
      
      [Groups: letters (n=2)]
      

      【讨论】:

        猜你喜欢
        • 2017-04-16
        • 1970-01-01
        • 2022-01-10
        • 1970-01-01
        • 2014-03-17
        • 1970-01-01
        • 1970-01-01
        • 2019-08-01
        • 1970-01-01
        相关资源
        最近更新 更多