【问题标题】:dplyr NSE mode in a function: nested conditions函数中的 dplyr NSE 模式:嵌套条件
【发布时间】:2015-09-24 13:42:23
【问题描述】:

目标是转换数据框的列。示例如下:

  df <- data.frame( fact=c("dog",2,"NA",0,"cat",1,"Cat"),
              value=c(4,2,6,0,9,1,3) ); df$fact <- as.factor(df$fac)

  func <- function(data,fac,val){
          data <- data %>%  
          mutate_(fac= interp(~tolower(fac), fac=as.name(fac)) ) %>%
          mutate_(val= interp(~ifelse(fac=='cat',1*val,
                       ifelse(fac=='dog',2*val,0)), fac=as.name(fac), val=as.name(val)))
  return(data) } 

电话:

new.df <- func(df,"fact","value")

     fact value  fac val
   1  dog     4  dog  8
   2    2     2   2   0
   3   NA     6  na   0
   4    0     0   0   0
   5  cat     9 cat   9
   6    1     1   1   0
   7  Cat     3 cat   0

存在 2 个问题:(1)- 与“Cat”关联的值为 false;应该是 3*1=3 (2)- 理想情况下,调用返回原始 data.frame df 以及转换后的 fact 和 value 变量。

有什么想法吗?谢谢各位。

编辑:请注意df 有另一列third,它应该不受对fact 和value 的操作的影响。

【问题讨论】:

    标签: r function dplyr nse


    【解决方案1】:

    在 OP 的代码中,“val”是基于未修改的“fact”列创建的。如果我们使用第一个 mutate_ 中修改后的“fac”,则不需要as.name(fac)。

    library(lazyeval)
    library(dplyr)
    func <- function(data,fac,val){
          data <- data %>%  
                   mutate_(fac= interp(~tolower(fac), fac=as.name(fac))) %>%
                   mutate_(val= interp(~ifelse(fac=='cat',1*val,
                       ifelse(fac=='dog',2*val,0)), val=as.name(val)))
      return(data) } 
    
    func(df, 'fact', 'value')
    #  fact value fac val
    #1  dog     4 dog   8
    #2    2     2   2   0
    #3   NA     6  na   0
    #4    0     0   0   0
    #5  cat     9 cat   9
    #6    1     1   1   0
    #7  Cat     3 cat   3
    

    如果我们只需要返回修改后的列,请使用transmute_

    func1 <- function(data,fac,val){
          data <- data %>%  
                   transmute_(fac= interp(~tolower(fac), fac=as.name(fac)), 
                          val= interp(~ifelse(fac=='cat',1*val,
                             ifelse(fac=='dog',2*val,0)), val=as.name(val)))
         return(data) } 
    
    func1(df, 'fact', 'value')
    #  fac val
    #1 dog   8
    #2   2   0
    #3  na   0
    #4   0   0
    #5 cat   9
    #6   1   0
    #7 cat   3
    

    【讨论】:

    • @@akrun:非常感谢,不知道transmute。
    【解决方案2】:

    如果您想返回具有原始名称的 original 列(可能包括 data.frame 中的其他列),您可以使用稍微不同的 dplyr-approach 与 mutate_each 而不是 @ 987654322@:

    library(lazyeval)
    library(dplyr)
    
    func <- function(data,fac,val) {
      data %>%  
        mutate_each_(interp(~tolower(var), var = as.name(fac)), fac) %>% 
        mutate_each_(interp(~ifelse(col =='cat', var, ifelse(col == 'dog',2*var, 0)), 
                 var=as.name(val), col = as.name(fac)), val)
    }
    

    使用函数:

    func(df, "fact", "value")
    #  fact value
    #1  dog     8
    #2    2     0
    #3   na     0
    #4    0     0
    #5  cat     9
    #6    1     0
    #7  cat     3
    

    如果您希望保留数据中的其他列(而由于transmute,它们将被 akrun 的方法删除),则表明与 akruns 答案的区别:

    df$some_column <- letters[1:7]  # add a new column
    

    使用该函数后,其他列现在仍保留在您的数据中,并且修改后的列保留其原始名称:

    func(df, "fact", "value")
    #  fact value some_column
    #1  dog     8           a
    #2    2     0           b
    #3   na     0           c
    #4    0     0           d
    #5  cat     9           e
    #6    1     0           f
    #7  cat     3           g
    

    【讨论】:

    • @@docendo:我意识到 akrun 解决方案存在一个问题,我在问题中没有提到:df 有其他列(即变量)在对@987654329 进行转换后应该保持不受影响@ 和 value。知道如何实现这一目标吗?
    • @remi,您是否尝试过在我的回答中使用该功能?它正是这样做的。
    • @@docendo:确实,您的解决方案在我意识到之前解决了这个问题!考虑到tolower 操作,我还有另一个担心:-\:处理 NA。是否应该包括:na.omit() 来解决这个问题?
    猜你喜欢
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多