如果所有值均为NA

时间:2019-06-06 07:50:34

标签: r sum na

在模拟过程中,我创建了多个包含1,000,000个变量的数据集。但是,这些变量的某些值是NA,在某些情况下,甚至所有值都是NA。现在,我想计算变量所有值的总和,但是如果所有值均为NA,则想获得NA

公用sum(x, na.rm=T)sum(na.omit(x))的问题在于,如果所有值均为NA,它将返回0。因此,我编写了自己的函数,以预期的方式处理NA

sumna <- function(x) {
  sumna <- NULL
  return(ifelse(all(is.na(x)), NA, sum(na.omit(x))))
}

但是,该实现相当慢。

因此,我正在寻找一种实现或预先实现的函数,该函数求和向量的值,将NA省略,并在所有值均为NA的情况下返回NA

非常感谢!

5 个答案:

答案 0 :(得分:7)


sum_中的hablar与OP想要的行为相同。因此,无需重新发明轮子

library(hablar)
sum_(c(1:10, NA))
#[1] 55
sum_(c(NA, NA, NA))
#[1] NA

它可以在tidyversedata.table

中使用
library(dplyr)
df1 %>%
    summarise_all(sum_)

但是,如果我们需要更改OP的自定义功能,而不是ifelse,则更好的选择是if/else

sumna <- function(x) {
       if(all(is.na(x))) NA else sum(x, na.rm = TRUE)
   }

此外,我们可以使用向量化的colSums

v1 <- colSums(df1, na.rm = TRUE)
v1[colSums(is.na(df1)) == nrow(df1)] <- NA

由于数据集庞大,我们还可以利用高效的data.table

library(data.table)
setDT(df1)[, lapply(.SD, sumna)]

或使用tidyverse

library(tidyverse)
df1 %>%
     summarise_all(sumna)

答案 1 :(得分:4)

您可以删除所有NA,并测试长度是否大于0。

sumna_a <- function(x) {
    x <- na.omit(x)
    if(length(x)) return(sum(x))
    NA
}

#or
sumna_b <- function(x) {
    if(length(na.omit(x))) return(sum(x, na.rm = TRUE))
    NA
}

我认为,在大多数情况下,如果您仅使用sum(x, na.rm = TRUE)并随后在sum==0上进行测试,那么是否只有NA会比较有效:

sumna_c <- function(x) {
    ret <- sum(x, na.rm = TRUE)
    if(ret == 0 && all(is.na(x))) {NA} else {ret}
}

答案 2 :(得分:3)

您还可以根据xsumna <- function(x) { c(NA, sum(x, na.rm = TRUE))[(sum(is.na(x)) != length(x)) +1] } sumna(c(1:10, NA)) #[1] 55 sumna(c(NA, NA, NA)) #[1] NA sumna(1:5) #[1] 15 的数量来对值进行子集化

{{1}}

答案 3 :(得分:3)

在比较发布的方法时,在您的总和为!= 0且没有NA的情况下,user10488504 function c似乎是目前性能最高的。如果您只有NA的AntiRonakShahakrun很好:

sumna_Anti <- function(x) {
  sumna <- NULL
  return(ifelse(all(is.na(x)), NA, sum(na.omit(x))))
}

sumna_RonakShah <- function(x) {
   c(NA, sum(x, na.rm = TRUE))[(sum(is.na(x)) != length(x)) +1]
}

sumna_akrun <- function(x) {
       if(all(is.na(x))) NA else sum(x, na.rm = TRUE)
   }

sumna_user10488504_a <- function(x) {
    x <- na.omit(x)
    if(length(x)) return(sum(x))
    NA
}

sumna_user10488504_b <- function(x) {
    if(length(na.omit(x))) return(sum(x, na.rm = TRUE))
    NA
}

sumna_user10488504_c <- function(x) {
    ret <- sum(x, na.rm = TRUE)
    if(ret == 0 && all(is.na(x))) {NA} else {ret}
}

set.seed(0)
x <- rnorm(99999)

library(microbenchmark)
microbenchmark(sumna_Anti(x),
               sumna_RonakShah(x),
               sumna_akrun(x),
               sumna_user10488504_a(x),
               sumna_user10488504_b(x),
               sumna_user10488504_c(x)
               )

                    expr     min       lq      mean   median       uq      max neval  cld
           sumna_Anti(x) 307.288 310.0280 390.01838 319.2800 410.2040 2056.284   100    d
      sumna_RonakShah(x) 245.251 247.4715 269.40054 253.1650 259.7850  393.495   100  bc 
          sumna_akrun(x) 165.998 167.5005 209.39315 171.8925 190.8330 1768.761   100  b  
 sumna_user10488504_a(x) 221.275 222.6740 315.93037 229.0330 263.6405 1944.602   100   cd
 sumna_user10488504_b(x) 224.614 225.8170 261.77913 231.2305 234.6465 1934.120   100  bc 
 sumna_user10488504_c(x)  83.367  84.2610  86.16793  84.5900  86.4585  119.629   100 a   


x[sample(1:99999, 100)] <- NA
microbenchmark(sumna_Anti(x),
               sumna_RonakShah(x),
               sumna_akrun(x),
               sumna_user10488504_a(x),
               sumna_user10488504_b(x),
               sumna_user10488504_c(x)
               )

                    expr     min       lq      mean   median        uq      max neval  cld
           sumna_Anti(x) 607.367 628.4000 907.53974 634.3195  692.0845 4205.011   100    d
      sumna_RonakShah(x) 246.992 251.1290 273.80595 254.6195  261.4470  455.446   100  b  
          sumna_akrun(x) 167.058 168.5790 196.13280 170.4125  186.2650  373.708   100 ab  
 sumna_user10488504_a(x) 517.615 539.2940 684.20267 543.6295  582.5330 2360.247   100   c 
 sumna_user10488504_b(x) 523.769 544.6195 869.76645 558.0240 1125.6725 3914.266   100    d
 sumna_user10488504_c(x)  84.142  85.2940  89.04266  86.4255   87.4020  207.624   100 a   

x = rep(NA_real_, 99999)
microbenchmark(sumna_Anti(x),
               sumna_RonakShah(x),
               sumna_akrun(x),
               sumna_user10488504_a(x),
               sumna_user10488504_b(x),
               sumna_user10488504_c(x)
               )

           sumna_Anti(x)  243.848  252.3825  308.2693  260.5285  286.8025  2198.275   100  a 
      sumna_RonakShah(x)  242.706  249.3855  287.1426  258.8390  278.5905  1882.114   100  a 
          sumna_akrun(x)  240.459  244.9125  269.2847  255.1230  274.9215   409.886   100  a 
 sumna_user10488504_a(x) 1241.069 1285.3075 1534.1261 1343.7185 1486.4220  3117.453   100  ab
 sumna_user10488504_b(x) 1244.580 1281.9825 2461.2302 1349.9840 1427.9640 97590.279   100   b
 sumna_user10488504_c(x)  320.084  323.1905  353.9885  340.3555  358.7490   478.537   100  a 

答案 4 :(得分:2)

您可以使用colSums。假设您没有全为0的列,

ifelse(colSums(abs(df), na.rm = TRUE) == 0, NA, colSums(df, na.rm = TRUE))