【问题标题】:Equivalent of 'mutate_at' dplyr function in Python pandasPython pandas 中 'mutate_at' dplyr 函数的等价物
【发布时间】:2019-12-12 08:51:22
【问题描述】:

并在此先感谢您的帮助。

我希望通过将现有列的子集除以另一个现有列(使用后缀动态命名)来在 pandas 数据框中创建多个新列。下面是虚拟代码,说明了我想要做的一般要点,除了 25 列以上的各种转换。

R 代码

library(dplyr)

player = c('John','Peter','Michael')
min = c(20, 23, 35)
points = c(10,12,14)
rebounds = c(5,7,9)
assists = c(4,6,7)

df = data.frame(player,min,points,rebounds,assists)

df = df %>%
  mutate_at(vars(points:assists),.funs=funs(per_min=./min))

预期输出

 player min points rebounds assists points_per_min rebounds_per_min assists_per_min
1    John  20     10        5       4      0.5000000        0.2500000       0.2000000
2   Peter  23     12        7       6      0.5217391        0.3043478       0.2608696
3 Michael  35     14        9       7      0.4000000        0.2571429       0.2000000

我知道我可以在 pandas 中重现上述内容,如下所示:

import pandas as pd
data = pd.DataFrame({'player':['John','Peter','Michael'],
                     'min':[20,23,35],
                     'points':[10,12,14],
                     'rebounds':[5,7,9],
                     'assists':[4,6,7]})

df = pd.DataFrame(data)
df['points_per_minute'] = df['points']/df['min']
df['rebounds_per_minute'] = df['rebounds']/df['min']
df['assists_per_minute'] = df['assists']/df['min']

df.head()



 player  min  points  rebounds  assists  points_per_minute  rebounds_per_minute  assists_per_minute
0     John   20      10         5        4           0.500000             0.250000             0.20000
1    Peter   23      12         7        6           0.521739             0.304348             0.26087
2  Michael   35      14         9        7           0.400000             0.257143             0.20000

但是,我必须为 25 列以上的列执行此操作,并进行不同的转换,并且明确命名每一列和操作将变得相当麻烦。有熊猫复制吗?

【问题讨论】:

    标签: python r pandas dplyr


    【解决方案1】:

    类似于基础 R,通过基本算术的列块分配。通常,base R 可以更好地转换为 Numpy/Pandas。

    R

    cols <- c("points", "rebounds", "assists")
    df[paste0(cols, "_per_min")] <- df[cols] / df$min
    

    Python 熊猫

    cols = ["points", "rebounds", "assists"]
    df[[col+'_per_min' for col in cols]] = df[cols].div(df['min'], axis='index')
    

    【讨论】:

      【解决方案2】:

      方法1

      获取列列表(如果你没有列列表并且想要获取min列之后的所有列,请使用cols=df.iloc[:,df.columns.get_loc('min')+1:].columns

      cols=['points','rebounds','assists']
      

      通过df.loc[]add_suffix 将这些列的子集创建为_per_minute,然后将dividemin 列一起创建。

      m=df.loc[:,cols].add_suffix('_per_minute')
      df[m.columns]=m.div(df['min'],axis=0)
      print(df)
      

      方法2concat

      cols=['points','rebounds','assists']
      df=pd.concat([df,df.loc[:,cols].add_suffix('_per_minute').div(df['min'],axis=0)],axis=1)
      

      方法3

      使用相同的逻辑直接为它们分配字符串格式:

      cols=['points','rebounds','assists']
      df[[f"{i}_per_minute" for i in cols]]=df.loc[:,cols].div(df['min'],axis=0)
      print(df)
      

          player  min  points  rebounds  assists  points_per_minute  \
      0     John   20      10         5        4           0.500000   
      1    Peter   23      12         7        6           0.521739   
      2  Michael   35      14         9        7           0.400000   
      
         rebounds_per_minute  assists_per_minute  
      0             0.250000             0.20000  
      1             0.304348             0.26087  
      2             0.257143             0.20000  
      

      【讨论】:

      • 谢谢!我选择了方法 3,效果很好
      【解决方案3】:

      mutate_atmutateacross 取代。

      以下是在 python 中以dplyr 的方式进行操作的方法:

      >>> from datar.all import c, f, tibble, mutate, across
      >>> 
      >>> player = c('John','Peter','Michael')
      >>> min = c(20, 23, 35)
      >>> points = c(10,12,14)
      >>> rebounds = c(5,7,9)
      >>> assists = c(4,6,7)
      >>> 
      >>> df = tibble(player,min,points,rebounds,assists)
      >>> 
      >>> df = df >> mutate(
      ... #                                             f.min passed to lambda as y
      ...     across(f[f.points:f.assists], {'per_min': lambda x, y: x / y}, f.min)
      ... )
      >>> df
          player     min  points  rebounds  assists  points_per_min  rebounds_per_min  assists_per_min
        <object> <int64> <int64>   <int64>  <int64>       <float64>         <float64>        <float64>
      0     John      20      10         5        4        0.500000          0.250000          0.20000
      1    Peter      23      12         7        6        0.521739          0.304348          0.26087
      2  Michael      35      14         9        7        0.400000          0.257143          0.20000
      

      我是datar 包的作者。如果您有任何问题,请随时提交问题。

      【讨论】:

        【解决方案4】:

        为了让这个感觉更像 dplyr,我真的更喜欢方法链接解决方案,因为它们在语法上与管道 dplyr 代码相似。

        此解决方案使用pandas.DataFrame.assigndictionary unpacking

        updated_data = data.assign(**{f"{col}_per_minute": lambda x: x[col] / x["min"]
                                      for col in ["points", "rebounds", "assists"]})
        

        【讨论】:

          猜你喜欢
          • 2019-12-14
          • 2022-06-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-07-28
          • 2017-09-23
          • 1970-01-01
          相关资源
          最近更新 更多