根据条件进行突变,其中有许多列,每列都有不同的设置

时间:2018-11-15 23:11:13

标签: r dplyr conditional mutate

我一直在寻找但没有发现如何简化dplyr中的许多列。

我有此代码(有效):

library(dplyr)
library(magrittr)
data("PlantGrowth")
PlantGrowth %>% mutate (
  a=if_else(group=="ctrl", weight*2, weight*100),
  b=if_else(group=="ctrl", weight*1,5, weight/100),
  c=if_else(group=="ctrl", weight*4, weight*100),
  d=if_else(group=="ctrl", weight*5, weight/1000)
)

我不想重复这个条件。像这样:

PlantGrowth %>% mutate_if_foo (
  group=="ctrl",{
   a=weight*2,
   b=weight*1,5,
   c=weight*4,
   d=weight*5
  }
)%>% mutate_if_foo (
  group!="ctrl",{
   a=weight*100,
   b=weight/100),
   c=weight*100),
   d=weight/1000)
  }
)

我在mutate_ifmutate_allmutate_atcase_when上找到了很多答案,但是他们没有回答我的问题。

请使用dplyr / tidyverse。

预先感谢

编辑

我尝试过@Rohit_das关于函数的想法。

mtcars %>% ( function(df) { 
  if (df$am==1){
    df%>% mutate(
      a=df$mpg*3,
      b=df$cyl*10) 
   }else{ 
     df%>% mutate(
      a=df$disp*300,
      d=df$cyl*1000) 
   }
}) 

但是我有警告消息:

In if (df$am == 1) { : 
the condition has length > 1 
and only the first element will be used

3 个答案:

答案 0 :(得分:1)

不确定我是否在这里理解了这个问题。如果您只是想减少代码的冗长性,则只需创建一个自定义函数

customif = function(x,y) { 
   if_else(group=="ctrl", weight*x, weight*y)
}

然后您可以在mutate中以

形式调用此函数
PlantGrowth %>% mutate (
  a=customif(2,100),
  b=customif(1,5, 1/100),
  c=customif(4, 100),
  d=customif(5, 1/1000)
)

答案 1 :(得分:0)

我想我用purrr找到了一个很好的解决方案。它使用输入的数据帧,然后使用每一列的新输入来动态命名新列a:d。第一列将使用x = 2y = 100z = "a",然后是下一行,依此类推。像这样的函数式编程最酷的一点是,它很容易扩展。

library(tidyverse)

iterate <- tibble(x = c(2, 1.5, 4, 5),
                  y = c(100, 1/100, 100, 1/1000),
                  z = c("a", "b", "c", "d"))

fun <- function(x, y, z) {
  PlantGrowth %>% 
    mutate(!!z := if_else(group == "ctrl", weight * x, weight * y)) %>% 
    select(3)
}

PlantGrowth %>% 
  bind_cols(
    pmap_dfc(iterate, fun)
    ) %>% 
  as_tibble

哪一个给你相同的df:

# A tibble: 30 x 6
   weight group     a     b     c     d
    <dbl> <fct> <dbl> <dbl> <dbl> <dbl>
 1   4.17 ctrl   8.34  6.26  16.7  20.8
 2   5.58 ctrl  11.2   8.37  22.3  27.9
 3   5.18 ctrl  10.4   7.77  20.7  25.9
 4   6.11 ctrl  12.2   9.17  24.4  30.6
 5   4.5  ctrl   9     6.75  18    22.5

答案 2 :(得分:0)

我想我已经找到了答案。我在mtcars上进行了测试。我尚未在真实代码上进行测试。

如果我认为我的概念不对,请发表评论。

过滤器的条件必须是互斥的,否则我将重复一行。

        library(dplyr)
        library(magrittr)
        library(tibble) # only if necessary to preserve rownames
        mtcars %>% ( function(df) { 
                rbind(
                    (df 
                     %>% tibble::rownames_to_column(.) %>%tibble::rowid_to_column(.)  # to preserve rownames
                     %>%dplyr::filter(am==1) 
                     %>%dplyr::mutate(
                        a=mpg*3,
                        b=cyl*10,d=NA)),
                    (df 
                     %>% tibble::rownames_to_column(.) %>%tibble::rowid_to_column(.)  # to preserve rownames
                     %>%dplyr::filter(am!=1) 
                     %>%dplyr::mutate(
                      a=disp*3,
                      d=cyl*100,b=NA))
                )
        })     %>%arrange(rowid)