大家好,
library(dplyr)
library(tibble)
mtcars %>%
rownames_to_column("modelle") %>%
mutate_if(~is.numeric(.x) & mean(.x) > 50, ~(.x / 1000))
Warning message:
In mean.default(.x) : argument is not numeric or logical: returning NA
此错误似乎是由于字符向量引起的。它可以工作,但是仍然非常难看。我做错了什么,在这种情况下可以做得更好?
谢谢!
答案 0 :(得分:4)
R不会使向量化&
短路,因此它在所有列上同时运行 is.numeric
和mean
。由于您的第一列(modelle
)显然是character
,所以失败了。
但是,您实际上不需要对其进行矢量化处理。如果您从向量化的&
更改为二进制文件&&
,则R会使其短路并获得所需的行为。
mtcars %>%
rownames_to_column("modelle") %>%
mutate_if(~is.numeric(.x) && mean(.x) > 50, ~(.x / 1000)) %>%
head()
# modelle mpg cyl disp hp drat wt qsec vs am gear carb
# 1 Mazda RX4 21.0 6 0.160 0.110 3.90 2.620 16.46 0 1 4 4
# 2 Mazda RX4 Wag 21.0 6 0.160 0.110 3.90 2.875 17.02 0 1 4 4
# 3 Datsun 710 22.8 4 0.108 0.093 3.85 2.320 18.61 1 1 4 1
# 4 Hornet 4 Drive 21.4 6 0.258 0.110 3.08 3.215 19.44 1 0 3 1
# 5 Hornet Sportabout 18.7 8 0.360 0.175 3.15 3.440 17.02 0 0 3 2
# 6 Valiant 18.1 6 0.225 0.105 2.76 3.460 20.22 1 0 3 1
进一步证明&
没有短路。
mymean <- function(x, ...) {
if (is.character(x)) {
message("character?")
return(Inf) # this is certainly not the right thing to do in general ...
} else mean(x, ...)
}
mtcars %>%
rownames_to_column("modelle") %>%
mutate_if(~is.numeric(.x) & mymean(.x) > 50, ~(.x / 1000)) %>%
head()
# character?
# modelle mpg cyl disp hp drat wt qsec vs am gear carb
# 1 Mazda RX4 21.0 6 0.160 0.110 3.90 2.620 16.46 0 1 4 4
# 2 Mazda RX4 Wag 21.0 6 0.160 0.110 3.90 2.875 17.02 0 1 4 4
# 3 Datsun 710 22.8 4 0.108 0.093 3.85 2.320 18.61 1 1 4 1
# 4 Hornet 4 Drive 21.4 6 0.258 0.110 3.08 3.215 19.44 1 0 3 1
# 5 Hornet Sportabout 18.7 8 0.360 0.175 3.15 3.440 17.02 0 0 3 2
# 6 Valiant 18.1 6 0.225 0.105 2.76 3.460 20.22 1 0 3 1
如果发生短路 ,则mymean
将永远不会收到消息。 (出于以下几个原因,我认为这里的mymean
不是可行的替代方法:(1)使用Inf
仅仅是为了确保条件 outside 对mean
的调用有效,但是如果发生错误/警告并且预期会出现numeric
,则通常应返回NA
或NaN
,而不是返回数字...即使您可能不认为Inf
是一个实际可用的数字(2)它正在解决症状,而不是问题。问题是缺少简短向量化逻辑表达式中的循环。)
答案 1 :(得分:1)
您应使用“ &&”而不是“&”。第一个用于标量,第二个用于矢量。在您的情况下,平均值是标量。
library(dplyr)
library(tibble)
mtcars %>%
rownames_to_column("modelle") %>%
mutate_if(~is.numeric(.x) && mean(.x) > 50, ~(.x / 1000))