我想省略中行NA出现在这两个的2列.
我很熟悉na.omit,is.na和complete.cases,但无法弄清楚如何使用这些得到我想要的东西.例如,我有以下数据帧:
(df <- structure(list(x = c(1L, 2L, NA, 3L, NA),
y = c(4L, 5L, NA, 6L, 7L),
z = c(8L, 9L, 10L, 11L, NA)),
.Names = c("x", "y", "z"),
class = "data.frame",
row.names = c(NA, -5L)))
x y z
1 4 8
2 5 9
NA NA 10
3 6 11
NA 7 NA
Run Code Online (Sandbox Code Playgroud)
并且我想只删除那些NA出现在x和y列中的行(不包括z中的任何内容),以便给出
x y z
1 4 8
2 5 9
3 6 11
NA 7 NA
Run Code Online (Sandbox Code Playgroud)
有谁知道一个简单的方法来做到这一点?使用na.omit,is.na或complete.cases不工作.
akr*_*run 13
df[!with(df,is.na(x)& is.na(y)),]
# x y z
#1 1 4 8
#2 2 5 9
#4 3 6 11
#5 NA 7 NA
Run Code Online (Sandbox Code Playgroud)
我做了一个稍微大一点的数据集基准测试.结果如下:
set.seed(237)
df <- data.frame(x=sample(c(NA,1:20), 1e6, replace=T), y= sample(c(NA, 1:10), 1e6, replace=T), z= sample(c(NA, 5:15), 1e6,replace=T))
f1 <- function() df[!with(df,is.na(x)& is.na(y)),]
f2 <- function() df[rowSums(is.na(df[c("x", "y")])) != 2, ]
f3 <- function() df[ apply( df, 1, function(x) sum(is.na(x))>1 ), ]
library(microbenchmark)
microbenchmark(f1(), f2(), f3(), unit="relative")
Unit: relative
#expr min lq median uq max neval
# f1() 1.000000 1.000000 1.000000 1.000000 1.000000 100
# f2() 1.044812 1.068189 1.138323 1.129611 0.856396 100
# f3() 26.205272 25.848441 24.357665 21.799930 22.881378 100
Run Code Online (Sandbox Code Playgroud)
使用rowSums带is.na,就像这样:
> df[rowSums(is.na(df[c("x", "y")])) != 2, ]
x y z
1 1 4 8
2 2 5 9
4 3 6 11
5 NA 7 NA
Run Code Online (Sandbox Code Playgroud)
跳上基准测试车,并展示我所指的这是一个相当容易推广的解决方案,请考虑以下因素:
## Sample data with 10 columns and 1 million rows
set.seed(123)
df <- data.frame(replicate(10, sample(c(NA, 1:20),
1e6, replace = TRUE)))
Run Code Online (Sandbox Code Playgroud)
首先,如果你只对两个栏目感兴趣,那么这就是事情.这两种解决方案都非常清晰易读.速度非常接近.
f1 <- function() {
df[!with(df, is.na(X1) & is.na(X2)), ]
}
f2 <- function() {
df[rowSums(is.na(df[1:2])) != 2, ]
}
library(microbenchmark)
microbenchmark(f1(), f2(), times = 20)
# Unit: milliseconds
# expr min lq median uq max neval
# f1() 745.8378 1100.764 1128.047 1199.607 1310.236 20
# f2() 784.2132 1101.695 1125.380 1163.675 1303.161 20
Run Code Online (Sandbox Code Playgroud)
接下来,我们来看看同样的问题,但这一次,我们正在考虑NA前5列的值.此时,rowSums方法稍微快一点,语法也没有太大变化.
f1_5 <- function() {
df[!with(df, is.na(X1) & is.na(X2) & is.na(X3) &
is.na(X4) & is.na(X5)), ]
}
f2_5 <- function() {
df[rowSums(is.na(df[1:5])) != 5, ]
}
microbenchmark(f1_5(), f2_5(), times = 20)
# Unit: seconds
# expr min lq median uq max neval
# f1_5() 1.275032 1.294777 1.325957 1.368315 1.572772 20
# f2_5() 1.088564 1.169976 1.193282 1.225772 1.275915 20
Run Code Online (Sandbox Code Playgroud)
您可以申请切片行:
sel <- apply( df, 1, function(x) sum(is.na(x))>1 )
Run Code Online (Sandbox Code Playgroud)
然后您可以选择:
df[ sel, ]
Run Code Online (Sandbox Code Playgroud)
要忽略z列,只需从apply中省略它:
sel <- apply( df[,c("x","y")], 1, function(x) sum(is.na(x))>1 )
Run Code Online (Sandbox Code Playgroud)
如果他们都必须TRUE,只需稍微改变一下这个功能:
sel <- apply( df[,c("x","y")], 1, function(x) all(is.na(x)) )
Run Code Online (Sandbox Code Playgroud)
这里的其他解决方案更具体针对这一特定问题,但apply值得学习,因为它解决了许多其他问题.成本是速度(关于小数据集和速度测试的常见警告适用):
> microbenchmark( df[!with(df,is.na(x)& is.na(y)),], df[rowSums(is.na(df[c("x", "y")])) != 2, ], df[ apply( df, 1, function(x) sum(is.na(x))>1 ), ] )
Unit: microseconds
expr min lq median uq max neval
df[!with(df, is.na(x) & is.na(y)), ] 67.148 71.5150 76.0340 86.0155 1049.576 100
df[rowSums(is.na(df[c("x", "y")])) != 2, ] 132.064 139.8760 145.5605 166.6945 498.934 100
df[apply(df, 1, function(x) sum(is.na(x)) > 1), ] 175.372 184.4305 201.6360 218.7150 321.583 100
Run Code Online (Sandbox Code Playgroud)
dplyr 解决方案
require("dplyr")
df %>% filter_at(.vars = vars(x, y), .vars_predicate = any_vars(!is.na(.)))
Run Code Online (Sandbox Code Playgroud)
可以使用.vars参数修改为采用任意数量的列
更新: dplyr 1.0.4
require("dplyr")
df %>% filter_at(.vars = vars(x, y), .vars_predicate = any_vars(!is.na(.)))
Run Code Online (Sandbox Code Playgroud)
看到类似的答案:https : //stackoverflow.com/a/66136167/6105259