假设您有以下数据框:
dat <- data.frame(a = c(1:3, NA), b = c(letters[1:3], NA), c = NA)
> dat
a b c
1 1 a NA
2 2 b NA
3 3 c NA
4 NA <NA> NA
如何以非常有效的方式选择非NA区域?
这是我目前使用的:
ensureNonNaRange <- function(dat) {
idx_col <- ! sapply(dat, function(ii) all(is.na(ii)))
idx_row <- ! sapply(1:nrow(dat), function(ii) all(is.na(unlist(dat[ii, ]))))
dat[idx_row, idx_col]
}
> ensureNonNaRange(dat)
a b
1 1 a
2 2 b
3 3 c
就在今天,我才注意到之前我还不知道的非常有用的功能type.convert
,我认为可能还存在一些东西,而且还有一些东西。喜欢基地R的这个任务。
根据我得到的答案/评论进行一些比较:
ensureNonNaRange2 <- function(dat) {
dat[rowSums(!is.na(dat)) != 0, colSums(!is.na(dat)) != 0]
}
microbenchmark::microbenchmark(
a = ensureNonNaRange(dat),
b = ensureNonNaRange2(dat)
)
Unit: microseconds
expr min lq mean median uq max neval
a 296.178 310.1070 346.2259 329.0210 349.9875 680.035 100
b 112.313 120.0845 134.1716 125.6555 133.7200 338.112 100
答案 0 :(得分:2)
虽然可能还有一些内置函数可以执行此操作,但您可以使用子集进行此操作。
当is.na
传递整个data.frame
时,它会生成一个布尔掩码,因此如果对!is.na(dat)
的行和列求和(即添加TRUE
值什么是 not NA
),对于只有 NA
s的行和列,您得到的总和为零。
因此,如果我们按行和列总和为!= 0
时的子集,我们会留下非NA
值的行和列:
> dat[rowSums(!is.na(dat)) != 0, colSums(!is.na(dat)) != 0]
a b
1 1 a
2 2 b
3 3 c
如果行或列中的某些但不是全部值都是NA,则此方法会留下该行/列:
> dat[2,2] <- NA
> dat[rowSums(!is.na(dat)) != 0, colSums(!is.na(dat)) != 0]
a b
1 1 a
2 2 <NA>
3 3 c
(如果您希望使用任何 NA
来删除行/列,请调整感叹号,或使用complete.cases
。)
此外,它应该非常超快,因为rowSums
和colSums
已经过高度优化,因此它仍然可以在庞大的数据结构上快速运行。