sapply 和 apply 使用 is.character() 给出不同的结果

sapply and apply give different results with is.character()

我试图转换以降低我的数据框的字符类型的特征,并发现了这个 post:
tolower
我在几个 data.frames 上构建了一个函数,最后发现我的所有特征都被视为字符!

mytolower <- function(p_vector){
  if (is.character(p_vector)) return(tolower(iconv(enc2utf8(p_vector), sub = "byte")))
  else return(p_vector)
}
for (df in c("train", "test")) as.data.frame(apply(get(df), 2, function(x) mytolower(x)), stringsAsFactors = FALSE)

在 Whosebug 上看起来更好,我发现第二个 post 通过使用 lapply 部分解决了问题,但奇怪的是,它暗示 apply 和 sapply 以类似的方式工作
lapply rather than apply
因此,我终于建立了这个基本上可以说明我的麻烦的例子:

train <- data.frame(v1=1:3, v2=c("a","b","c"), v3=11:13, stringsAsFactors = FALSE)
str(train)
apply(train, 2, function(x) is.character(x)) #wrong
lapply(train, function(x) is.character(x)) #right
sapply(train, function(x) is.character(x)) #right
sapply(train, is.character) #right

虽然 apply 会将所有特征视为 "character",但 lapply 或 sapply 将能够区分数字和字符特征。为什么会这样?有没有办法让 apply 找到正确的答案? 谢谢

在应用 is.character() 之前,首先将 train 强制转换为矩阵。由于矩阵只包含单一类型的对象,因此所有元素都变成字符串。

来自 apply() 的帮助文件:

If X is not an array but an object of a class with a non-null dim value (such as a data frame), apply attempts to coerce it to an array via as.matrix if it is two-dimensional (e.g., a data frame) or via as.array.

我建议使用 dplyr 中的 mutate_if() 函数。

library(dplyr)
mutate_if(train, is.character, toupper)

#    v1 v2 v3
#    1  1  A 11
#    2  2  B 12
#    3  3  C 13

apply 函数需要一个矩阵或数组作为输入,它会强制转换您提供给它的数据帧,并且 as.matrix() 转换会将所有数组转换为字符数组,因为所有列都将到来出来是字符型的。