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()
不像你那样工作。在它的帮助页面中,它说设置条件的第二个参数需要是以下两种情况之一:
- 要应用于列的谓词函数。 (此时可以是普通函数,也可以是lambda函数,即
~ fun(.)
的形式)
- 一个逻辑向量。
如果要计算字符列的均值,正确的语法是
代码 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 2 在 names(.)
前面没有 ~
符号的情况下工作正常?原因是 names
中的 "."
实际上代表 df
本身 而不是 df
中的每一列,因为管道运算符 (%>%
)。因此,代码2实际上等同于
执行
df %>% mutate_if(names(df) %in% varnames,funs(mean(as.numeric(.))))
其中传递给它的是逻辑向量而不是谓词函数。 names(df) %in% varnames
returns TRUE FALSE TRUE FALSE
因此选择了 a
和 c
。这可以解释为什么你的第一个块失败但最后一个有效。
第一块
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
,因此未选择任何列。最后一个区块也是如此。
真的很困惑为什么这不起作用:
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()
不像你那样工作。在它的帮助页面中,它说设置条件的第二个参数需要是以下两种情况之一:
- 要应用于列的谓词函数。 (此时可以是普通函数,也可以是lambda函数,即
~ fun(.)
的形式) - 一个逻辑向量。
如果要计算字符列的均值,正确的语法是
代码 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 2 在 names(.)
前面没有 ~
符号的情况下工作正常?原因是 names
中的 "."
实际上代表 df
本身 而不是 df
中的每一列,因为管道运算符 (%>%
)。因此,代码2实际上等同于
df %>% mutate_if(names(df) %in% varnames,funs(mean(as.numeric(.))))
其中传递给它的是逻辑向量而不是谓词函数。 names(df) %in% varnames
returns TRUE FALSE TRUE FALSE
因此选择了 a
和 c
。这可以解释为什么你的第一个块失败但最后一个有效。
第一块
df %>% mutate_if(is.character(.) & names(.) %in% varnames,
funs(mean(as.numeric(.))))
将所有"."
替换为df
,可以找到
is.character(df)
returnsFALSE
names(df) %in% varnames
returnsTRUE FALSE TRUE FALSE
&
运算符构成最终条件 FALSE FALSE FALSE FALSE
,因此未选择任何列。最后一个区块也是如此。