在模拟过程中,我创建了多个包含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
。
非常感谢!
答案 0 :(得分:7)
sum_
中的hablar
与OP想要的行为相同。因此,无需重新发明轮子
library(hablar)
sum_(c(1:10, NA))
#[1] 55
sum_(c(NA, NA, NA))
#[1] NA
它可以在tidyverse
或data.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)
您还可以根据x
中sumna <- 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的Anti,RonakShah和akrun很好:
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))