【问题标题】:Is it possible to skip NA values in "+" operator?是否可以在“+”运算符中跳过 NA 值?
【发布时间】:2017-12-31 20:43:27
【问题描述】:

我想在 R 中计算一个方程。我不想使用函数 sum,因为它返回 1 个值。我想要完整的值向量。

x = 1:10
y = c(21:29,NA)
x+y
 [1] 22 24 26 28 30 32 34 36 38 NA

x = 1:10
y = c(21:30)
x+y
 [1] 22 24 26 28 30 32 34 36 38 40

我不想要:

sum(x,y, na.rm = TRUE)
[1] 280

不返回向量。

这是一个玩具示例,但我有一个更复杂的方程,它使用长度为 84647 个元素的多个向量。

这是我的意思的另一个例子:

x = 1:10
y = c(21:29,NA)
z = 11:20
a = c(NA,NA,NA,30:36)
5 +2*(x+y-50)/(x+y+z+a) 
 [1]       NA       NA       NA 4.388889 4.473684 4.550000 4.619048 4.681818 4.739130       NA

【问题讨论】:

  • 获取连接向量的行和。 rowSums(cbind(x,y), na.rm = T)
  • 好的,所以你可以把它放在数据框格式中。不能直接将它们用作向量吗? apply(cbind(x,y), 1, function(x) sum(x, na.rm = T))
  • cbind 创建矩阵,而不是数据框。 rowSums 已经过优化,会非常快,比apply(..., 1, sum, na.rm = T) 更快。
  • 跳过 复杂表达式中的 NA 不需要使用自定义的 +。您可以简单地跳过最终结果向量中的 NA,例如res<-res[!is.na(res)],这也避免了最终对不同长度的向量求和的风险(在不同数量的 NA 的情况下)。如果您想用零替换 NA,那就是另一回事了...

标签: r vector sum lapply cbind


【解决方案1】:

1) %+% 定义自定义+运算符:

`%+%` <- function(x, y)  mapply(sum, x, y, MoreArgs = list(na.rm = TRUE))
5 + 2 * (x %+% y - 50) / (x %+% y %+% z %+% a)

给予:

[1] 3.303030 3.555556 3.769231 4.388889 4.473684 4.550000 4.619048 4.681818
[9] 4.739130 3.787879

这里有一些简单的例子:

1 %+% 2
## [1] 3

NA %+% 2
## [1] 2

2 %+% NA
## [1] 2

NA %+% NA
## [1] 0

2) na2zero 另一种可能性是定义一个将 NA 映射到 0 的函数,如下所示:

na2zero <- function(x) ifelse(is.na(x), 0, x)

X <- na2zero(x)
Y <- na2zero(y)
Z <- na2zero(z)
A <- na2zero(a)

5 + 2 * (X + Y - 50) / (X + Y + Z + A)

给予:

[1] 3.303030 3.555556 3.769231 4.388889 4.473684 4.550000 4.619048 4.681818
[9] 4.739130 3.787879

3) 结合上述 结合(1) 和(2) 中的想法的变体是:

X <- x %+% 0
Y <- y %+% 0
Z <- z %+% 0
A <- a %+% 0

5 + 2 * (X + Y - 50) / (X + Y + Z + A)

4) numeric0 类 我们可以定义一个自定义类"numeric0",带有自己的+运算符:

as.numeric0 <- function(x) structure(x, class = "numeric0")
`+.numeric0` <- `%+%`

X <- as.numeric0(x)
Y <- as.numeric0(y)
Z <- as.numeric0(z)
A <- as.numeric0(a)

5 + 2 * (X + Y - 50) / (X + Y + Z + A)

注意:使用的输入是问题中的输入,即:

x = 1:10
y = c(21:29,NA)
z = 11:20
a = c(NA,NA,NA,30:36)

【讨论】:

  • 我试图找到一种方法来使用 mapply 并获得四个单独的向量 (X, Y, Z, A)。出于好奇,有可能吗? (p.s.抱歉编辑,我看到一个错字)
  • 你可以这样做attach(lapply(list(X = x, Y = y, Z = z, A = a), na2zero))with(lapply(...), ...expression in X, Y, Z, A...)
【解决方案2】:

使用rowSums

要详细说明我的评论,您可以连接这些向量,然后将您的计算应用于结果矩阵。这是您在问题末尾提供的示例的解决方案;

5 + 2 * (rowSums(cbind(x,y), na.rm = T)-50)/(rowSums(cbind(x,y,z,a), na.rm = T))

#  [1] 3.303030 3.555556 3.769231 4.388889 4.473684 4.550000 4.619048 4.681818 
#  [9] 4.739130 3.787879

替换NA

我在这里看到了用向量中替换NA 的想法的解决方案;我认为这也会有所帮助:

y[is.na(y)] <- 0 #indexing NA values and replacing with zero

【讨论】:

    【解决方案3】:

    你可以使用ifelse()

    x = 1:10
    y = c(21:29,NA)
    x+y
    
    [1] 22 24 26 28 30 32 34 36 38 NA
    
    x + ifelse(is.na(y), 0, y)
    
    [1] 22 24 26 28 30 32 34 36 38 10
    

    【讨论】:

      【解决方案4】:

      数据

      x = 1:10
      y = c(21:29,NA)
      x+y
      # [1] 22 24 26 28 30 32 34 36 38 NA
      

      1

      foo1 = function(...){
          return(rowSums(cbind(...), na.rm = TRUE))
      }
      foo1(x, y)
      # [1] 22 24 26 28 30 32 34 36 38 10
      

      2

      foo2 = function(...){
          Reduce('+', lapply(list(...), function(x) replace(x, is.na(x), 0)))
      }
      foo2(x, y)
      # [1] 22 24 26 28 30 32 34 36 38 10
      

      【讨论】:

      • 无需转到data.frame,而是使用cbind() 将其保留为矩阵并避免额外的转换(rowSums 只会转换回矩阵)。
      【解决方案5】:

      仅供参考:

      x=1:10
      y=c(21:29, NA)
      
      "[<-"(x, is.na(x), 0) + "[<-"(y, is.na(y), 0)
      # [1] 22 24 26 28 30 32 34 36 38 10
      

      这再次说明了 R 中的所有内容都是函数(并且还表明 R 解释器足够聪明,可以在需要时将字符串转换为函数)。

      句法上的甜美:

      na.zero <- function(x)
      {
          "[<-"(x, is.na(x), 0)
      }
      na.zero(x) + na.zero(y)
      # [1] 22 24 26 28 30 32 34 36 38 10
      

      更广泛适用的版本:

      na.replace <- function(x, value)
      {
          "[<-"(x, is.na(x), value)
      }
      na.replace(x, 1) * na.replace(x, 1)
      # [1]   1   4   9  16  25  36  49  64  81 100
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-10-08
        • 2014-10-16
        • 2015-01-01
        • 2012-09-04
        • 2010-10-20
        • 2010-10-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多