dplyr::mutate_if() 具有多个条件,包括列 class 不工作

dplyr::mutate_if() with multiple conditions including column class not working

真的很困惑为什么这不起作用:

df <- data.frame(a = c("1", "2", "3"),
                   b = c(2, 3, 4),
                   c = c(4, 3, 2),
                   d = c("1", "5", "9"))
  
varnames = c("a", "c")
  
df %>% 
  mutate_if((is.character(.) & names(.) %in% varnames),
            funs(mean(as.numeric(.)))) 
  a b c d
1 1 2 4 1
2 2 3 3 5
3 3 4 2 9

预期输出为

  a b c d
1 2 2 4 1
2 2 3 3 5
3 2 4 2 9

它适用于单一条件,但 class 条件我实际上只能使用这个公式来工作(我不知道如何与列名条件结合):

df %>% 
  mutate_if(function(col) is.character(col),
              funs(mean(as.numeric(.)))) 
  a b c d
1 2 2 4 5
2 2 3 3 5
3 2 4 2 5

但是 is.factor 似乎可以很好地处理列名?

df %>% 
    mutate_if(!is.factor(.)  & (names(.) %in% varnames),
              funs(mean(as.numeric(.)))) 
  a b c d
1 2 2 3 1
2 2 3 3 5
3 2 4 3 9

请注意,mutate_if 正在逐步被 across 取代,因此以下内容可能是您想要的...

df %>% 
    mutate(across(where(is.character) & matches(varnames), ~mean(as.numeric(.))))

  a b c d
1 2 2 4 1
2 2 3 3 5
3 2 4 2 9

mutate_if() 不像你那样工作。在它的帮助页面中,它说设置条件的第二个参数需要是以下两种情况之一:

  1. 要应用于列的谓词函数。 (此时可以是普通函数,也可以是lambda函数,即~ fun(.)的形式)
  2. 一个逻辑向量。

如果要计算字符列的均值,正确的语法是

代码 1:
df %>% mutate_if(~ is.character(.), funs(mean(as.numeric(.))))

而不是

df %>% mutate_if(is.character(.), funs(mean(as.numeric(.))))

这会导致错误消息。那么,我们来说说下面的代码:

代码 2:
df %>% mutate_if(names(.) %in% varnames, funs(mean(as.numeric(.))))

理论上,mutate_if 只提取列值,不提取列名,因此 ~ names(.) 应该没有意义。但是为什么 Code 2names(.) 前面没有 ~ 符号的情况下工作正常?原因是 names 中的 "." 实际上代表 df 本身 而不是 df 中的每一列,因为管道运算符 (%>%)。因此,代码2实际上等同于

执行
df %>% mutate_if(names(df) %in% varnames,funs(mean(as.numeric(.))))

其中传递给它的是逻辑向量而不是谓词函数。 names(df) %in% varnames returns TRUE FALSE TRUE FALSE 因此选择了 ac。这可以解释为什么你的第一个块失败但最后一个有效。


第一块
df %>% mutate_if(is.character(.) & names(.) %in% varnames,
                 funs(mean(as.numeric(.)))) 

将所有"."替换为df,可以找到

  • is.character(df) returns FALSE
  • names(df) %in% varnames returns TRUE FALSE TRUE FALSE

& 运算符构成最终条件 FALSE FALSE FALSE FALSE,因此未选择任何列。最后一个区块也是如此。