Rei*_*ein 12 r data.table
我试图计算每行不包含NA的列数,并将该值放入该行的新列中.
示例数据:
library(data.table)
a = c(1,2,3,4,NA)
b = c(6,NA,8,9,10)
c = c(11,12,NA,14,15)
d = data.table(a,b,c)
> d
a b c
1: 1 6 11
2: 2 NA 12
3: 3 8 NA
4: 4 9 14
5: NA 10 15
Run Code Online (Sandbox Code Playgroud)
我想要的输出将包括一个新列num_obs,其中包含每行非NA条目的数量:
a b c num_obs
1: 1 6 11 3
2: 2 NA 12 2
3: 3 8 NA 2
4: 4 9 14 3
5: NA 10 15 2
Run Code Online (Sandbox Code Playgroud)
我现在已经阅读了好几个小时,到目前为止,我所提出的最好的是循环遍历行,我知道这在R或data.table中是不可取的.我相信有更好的方法可以做到这一点,请赐教.
我糟糕的方式:
len = (1:NROW(d))
for (n in len) {
d[n, num_obs := length(which(!is.na(d[n])))]
}
Run Code Online (Sandbox Code Playgroud)
the*_*ail 16
尝试使用这个Reduce链接一起+调用:
d[, num_obs := Reduce(`+`, lapply(.SD,function(x) !is.na(x)))]
Run Code Online (Sandbox Code Playgroud)
如果速度至关重要,那么您可以通过Ananda建议硬编码被评估的列数来更多地了解一下:
d[, num_obs := 4 - Reduce("+", lapply(.SD, is.na))]
Run Code Online (Sandbox Code Playgroud)
使用Ananda更大的数据进行基准测试.d来自上方:
fun1 <- function(indt) indt[, num_obs := rowSums(!is.na(indt))][]
fun3 <- function(indt) indt[, num_obs := Reduce(`+`, lapply(.SD,function(x) !is.na(x)))][]
fun4 <- function(indt) indt[, num_obs := 4 - Reduce("+", lapply(.SD, is.na))][]
library(microbenchmark)
microbenchmark(fun1(copy(d)), fun3(copy(d)), fun4(copy(d)), times=10L)
#Unit: milliseconds
# expr min lq mean median uq max neval
# fun1(copy(d)) 3.565866 3.639361 3.912554 3.703091 4.023724 4.596130 10
# fun3(copy(d)) 2.543878 2.611745 2.973861 2.664550 3.657239 4.011475 10
# fun4(copy(d)) 2.265786 2.293927 2.798597 2.345242 3.385437 4.128339 10
Run Code Online (Sandbox Code Playgroud)
快速想到的两个选项是:
d[, num_obs := sum(!is.na(.SD)), by = 1:nrow(d)][]
d[, num_obs := rowSums(!is.na(d))][]
Run Code Online (Sandbox Code Playgroud)
第一个工作是通过创建每组只有一行的"组"(1:nrow(d)).没有它,它只会将NA整个表中的值相加.
第二个使用已经非常有效的基本R函数,rowSums.
以下是大数据的基准:
set.seed(1)
nrow = 10000
ncol = 15
d <- as.data.table(matrix(sample(c(NA, -5:10), nrow*ncol, TRUE), nrow = nrow, ncol = ncol))
fun1 <- function(indt) indt[, num_obs := rowSums(!is.na(indt))][]
fun2 <- function(indt) indt[, num_obs := sum(!is.na(.SD)), by = 1:nrow(indt)][]
library(microbenchmark)
microbenchmark(fun1(copy(d)), fun2(copy(d)))
# Unit: milliseconds
# expr min lq mean median uq max neval
# fun1(copy(d)) 3.727958 3.906458 5.507632 4.159704 4.475201 106.5708 100
# fun2(copy(d)) 584.499120 655.634889 684.889614 681.054752 712.428684 861.1650 100
Run Code Online (Sandbox Code Playgroud)
顺便说一句,空[]的只是打印结果data.table.当您想要从set*"data.table"中的函数返回输出时,这是必需的.