R:tapply(长度)给NAs带​​来不同的结果

时间:2018-02-07 19:54:36

标签: r user-defined-functions na tapply

根据我是否使用

,我得到了包含NA的子集化参数的不同结果
tapply(X[X==Y], IND[X==Y], length)

tapply(X, IND, function(x){length(x[x==Y])})

简介:length()与NA不符合天真的期望:

> vec <- c(1,2,3,NA,5,6,NA,8,NA,10)
> length(vec)
[1] 10
> length(is.na(vec))  # Not talking about the same vector
[1] 10
> length(vec[vec==1])  # Sometimes I forget what vector I meant
[1] 4

对于粗心大意的人来说是惊喜,但这种方式是有原因的;这是预期的行为。但是第二个更长的tapply()调用遵循这种模式,而第一个版本给出了天真的期望。

设定:

set.seed(668)
yrCodes <- c(1995:2015)
staCodes <- c(LETTERS[1:12])
sexCodes <- c('m','f')
years <- rep(yrCodes, times=rep(sample(1:4, length(yrCodes), replace=TRUE)))
stations <- sample(staCodes, length(years), replace=TRUE)
sexes <- sample(sexCodes, length(years), replace=TRUE)
sexes[sample(1:length(sexes),10)] <- NA
data <- data.frame(YEAR=years, STATION=stations, SEX=sexes)

第一种形式:

> with(data, tapply(SEX, STATION, length))  # All observations
A B C D E F G H I J K L 
4 5 7 4 3 6 2 3 3 4 6 4 
> with(data, tapply(SEX[SEX=='m'], STATION[SEX=='m'], length))  # Males
 A  B  C  D  E  F  G  H  I  J  K  L 
 2  3  4  3 NA  2  2  3  2  2  2  2 
> with(data, tapply(SEX[SEX=='f'], STATION[SEX=='f'], length))  # Females
 A  B  C  D  E  F  G  H  I  J  K  L 
 1  1  1 NA  3  2 NA NA  1  1  3  1 
> with(data, tapply(SEX[is.na(SEX)], STATION[is.na(SEX)], length))  # NAs
 A  B  C  D  E  F  G  H  I  J  K  L 
 1  1  2  1 NA  2 NA NA NA  1  1  1 

这是粗心的人所期望的,但它与上面length(vec[])的情况不符。但是,这样做:

> with(data, tapply(SEX, STATION, function(sex){length(sex[sex=='m'])}))  # Males plus NAs
A B C D E F G H I J K L 
3 4 6 4 0 4 2 3 2 3 3 3 
> with(data, tapply(SEX, STATION, function(sex){length(sex[sex=='f'])}))  # Females plus NAs
A B C D E F G H I J K L 
2 2 3 1 3 4 0 0 1 2 4 2 
> with(data, tapply(SEX, STATION, function(sex){length(sex[is.na(sex)])}))  # NAs
A B C D E F G H I J K L 
1 1 2 1 0 2 0 0 0 1 1 1 

可能在臭名昭着的tapply文档中给出了差异的原因,但我无法弄明白。这是怎么回事?

编辑:哦是的 - 我也注意到第二种方式产生零,其中第一种只产生NA;在调用length时必须有显着差异 - 但是什么?

1 个答案:

答案 0 :(得分:0)

这是因为使用NA进行子集化会产生NA

"m" == NA
[1] NA

在您的通话中,您可以在不同的地方进行此操作。

考虑一下:

split(c(1,2,3), factor(c(1,2,3)))
$`1`
[1] 1

$`2`
[1] 2

$`3`
[1] 3

但因素为NA

split(c(1,2,3), factor(c(1,2,NA)))
$`1`
[1] 1

$`2`
[1] 2

split会自动忽略NAsplittapply的主要部分。

让我们看一下您使用的tapply中的两个:

with(data, tapply(SEX[SEX=='m'], STATION[SEX=='m'], length))

此处,您在>传递给tapply之前将分组。因此,STATION SEX NA NA的值现在也是splitsplit(data$SEX[data$SEX == "m"], as.factor(as.numeric(data$STATION[data$SEX == "m"]))) 会自动省略它们。

with(data, tapply(SEX, STATION, function(sex){length(sex[sex=='m'])}))

另一个:

tapply

此处,您在传递给split(c(1, NA, 2), factor(c(1, 2, 3)))

后将分组

NA当然还会包含split(data$SEX, as.factor(as.numeric(data$STATION))) 值。

[1] f    m    m    <NA>
Levels: f m

产量,例如对于第一个因素

NA == "m"

而且,正如您所提到的,NA将是NA。这就是你保持c(2, 3, 4)[c(1, NA)] [1] 2 NA 这种方式的原因。

{{1}}