使用R,我最近对使用某个因子时的sapply输出感到惊讶。看看以下内容:
> F <- as.factor(c("A", "B", "C", "D", "E", "F"))
> sapply(F, function(x) x)
[1] A B C D E F
Levels: A B C D E F
> sapply(F, function(x) (x=="C"))
[1] FALSE FALSE TRUE FALSE FALSE FALSE
到目前为止,这两项产出都符合预期。但现在,它变得很奇怪:
> sapply(F, function(x) if (TRUE) x else NA)
[1] A B C D E F
Levels: A B C D E F
> sapply(F, function(x) if (x=="C") x else NA)
[1] NA NA 3 NA NA NA
> sapply(F, function(x) {if (x=="C") foo <- "bar"; x})
[1] A B C D E F
Levels: A B C D E F
在这三种情况下,第一次和最后一次结果都是我所期望的。第二个是奇怪的:我希望得到类似[1] NA NA "C" NA NA NA
的东西。
我的第一个猜测是,比较(x=="C")
对if子句中的x
值有一些影响。 (不在条款之外,否则我们将在上一个案例中得到另一个结果。)可能x
被视为条款内的索引。
然而,这种猜测与以下两个观察结果不相符:
> sapply(F, function(x) if (x==x) x else NA)
[1] A B C D E F
Levels: A B C D E F
> sapply(F, function(x) if (x=="C") F[x] else NA)
[1] NA NA 3 NA NA NA
在这里,(x==x)
似乎没有任何影响力,如果x
是其子句中的索引,我们会取回"C"
而不是3
一个{{1}}。
我的实际问题是:为什么会这样? (到现在为止,我非常确定这是一个因素相关的功能,我不知道......)
答案 0 :(得分:3)
sapply
基本上是lapply
,后跟simplify2array
,在这种情况下只是调用unlist
。
首先让我们检查行为是否由lapply
:
lapply(F, function(x) if (x=="C") x else NA)
#[[1]]
#[1] NA
#
#[[2]]
#[1] NA
#
#[[3]]
#[1] C
#Levels: A B C D E F
#
#[[4]]
#[1] NA
#
#[[5]]
#[1] NA
#
#[[6]]
#[1] NA
如您所见,第三个元素仍然是一个因素。但是,NA
值属于“逻辑”类:
class(lapply(F, function(x) if (x=="C") x else NA)[[1]])
#[1] "logical"
这意味着来自help("unlist")
的两个引号是相关的:
特别对待因素。如果x的所有非列表元素都是 因素(或有序因素)然后结果将是一个因素 按顺序级别元素的级别集合的并集 级别出现在元素的级别集中(这意味着如果 所有元素都具有相同的级别集,即级别集 结果)。
和
在可能的情况下,列表元素被强制转换为共同模式 不列表,结果通常最终成为一个字符向量。 矢量将被强制转换为最高类型的组件 层次结构NULL&lt;原始&lt;逻辑&lt;整数&lt;双&lt;复杂&lt; 字符&lt;列表&lt;表达式:pairlists被视为列表。
第二个引言描述了这里发生的事情;因子的共同模式(内部是具有属性的整数向量),逻辑值是整数。这就是你得到的。
如果您想确保从sapply
获取因子向量,请在NA
条件中创建因子else
:
sapply(F, function(x) if (x=="C") x else {is.na(x) <- TRUE; x})
#[1] <NA> <NA> C <NA> <NA> <NA>
#Levels: A B C D E F