【问题标题】:R: tapply(length) giving differing results with NAsR:tapply(length) 给出不同的结果与 NA
【发布时间】:2018-02-07 19:54:36
【问题描述】:

根据我是否使用包含 NA 的子集参数,我从 tapply 中得到不同的结果

tapply(X[X==Y], IND[X==Y], length)

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

简介:带有 NA 的 length() 的行为不符合天真的期望:

> 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 的调用肯定有很大的不同——但是什么?

【问题讨论】:

    标签: r user-defined-functions na tapply


    【解决方案1】:

    这是因为使用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 自动省略了NAs,splittapply 的主要部分。

    让我们看看你使用的两个tapplys:

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

    在这里,您将 传递给tapply 之前进行子集化。因此,STATION 的值(其中SEXNA)现在也将是NAsplit 将自动忽略它们。

    split(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
    

    【讨论】:

    • 很好的答案——谢谢!我得到它。可惜那些粗心的人;这似乎是一个陷阱,我没有看到任何文档、提示、警告或任何会让我期待这一点的东西。 ?tapply 没有提到 split?split 没有提到自动 NA 遗漏(在某种程度上我可以理解)。无论如何,非常好的解释,如果可以的话,我会 +1,但我太弱了。
    猜你喜欢
    • 2019-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-01
    • 1970-01-01
    相关资源
    最近更新 更多