如何在R中删除只包含缺失值的行?

5

我有一个大的数据集,包含11列和100000行(以此类推),其中值为1、2、3、4。其中4是缺失值。有些行完全缺失,即所有11列都是4。例如:

"4"  "4"  "4"  "4"  "4"  "4"  "4"  "4"  "4"  "4"   "4"

现在我需要做的是仅删除那些完全缺失的行。简单来说,我想保留缺少小于11个值的行。 我已经使用了na.omit,但它在我的情况下不起作用。

提前致谢。


如何实现这一点可能取决于您未提供的信息。这是一个数据框还是矩阵?值存储为整数还是字符?尝试编辑您的问题,并运行 str(head(foo)) 命令,其中 foo 是您的数据。 - joran
6个回答

11
也许您最好的选择是利用R语言处理缺失值或NA值的习惯用法。一旦您编码了NA值,就可以使用complete.cases轻松实现您的目标。
创建一些带有缺失值(即值为4)的示例数据:
set.seed(123)
m <- matrix(sample(1:4, 30, prob=c(0.3, 0.3, 0.3, 0.1), replace=TRUE), ncol=6)
m[4, ] <- rep(4, 6)

将所有值等于4的值替换为NA:

m[m==4] <- NA
m
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    1    1   NA    2    2    2
[2,]    2    3    3    1    2    3
[3,]    3    2    2    1    2    3
[4,]   NA   NA   NA   NA   NA   NA
[5,]   NA    3    1   NA    2    1

现在你可以使用多种处理NA值的函数。例如,complete.cases函数将仅返回已完整的数据行:

m[complete.cases(m), ]

     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    2    3    3    1    2    3
[2,]    3    2    2    1    2    3

想要了解更多信息,请查看stats包中的?complete.cases?na.fail


这不是被问到的内容。OP想要删除仅完全缺失的行。 - Kenji

3
我在其他地方找到了这个解决方法,并使用 Andrie 的代码生成初始数据集,以下是具体步骤:
首先生成数据集:
set.seed(123)
m <- matrix(sample(1:4, 30, prob=c(0.3, 0.3, 0.3, 0.1), replace=TRUE), ncol=6)
m[4, ] <- rep(4, 6)
m[m==4] <- NA
m

这是初始数据集:

1    1    NA   2    2    2
2    3    3    1    2    3
3    2    2    1    2    3
NA   NA   NA   NA   NA   NA
NA   3    1    NA   2    1

现在删除只包含缺失观测值的行:

m[rowSums(is.na(m))<ncol(m),] 

以下是结果:

1    1    NA   2    2    2
2    3    3    1    2    3
3    2    2    1    2    3
NA   3    1    NA   2    1

2

一种真正快速的方法是使用一点数学。假设您的数据框称为datf。

rsum <- rowSums(datf)
datf <- datf[rowSums != 44,] #11 * 4

(适用于矩阵)

2
我不会给你负一分,但这种方法非常危险。它对于特定情况有效,但如果您添加/删除列会发生什么?始终尝试以健壮的方式解决问题。 - Andrie
1
这样做不行,因为一行的总和可以等于44,而并非所有元素都是4(例如:c(4,4,4,4,4,4,4,4,4,3,5))。 - Joshua Ulrich
请注意,此数据集中的值只能为1、2、3或4。 - John
而且,是的,它并不健壮,但如果作者想要快速执行,有时您需要为了速度编写非常具有针对性的函数... 有时您需要在健壮性和速度之间进行权衡。(我认为指出它缺乏健壮性是很好的...现在让我们为它非常非常快速地解决问题喝彩吧!) - John
@John:我同意有时你可能想在速度上做出鲁棒性的牺牲,但这不是其中的一个,因为你可以同时拥有两者(请看我的回答)。 - Joshua Ulrich
哦,我认为有很多快速的解决方案,Joshua,并且在针对性、强健和通用之间会有一个连续体... 我同意你的答案更快,稍微更强健... 并且它提供了一种将缺失值视为特殊情况的方法。不过,最终这是更快的。;) - John

2
这是我能想到的最快解决方案。我将使用类似于 @Andrie 的示例数据。
set.seed(21)
m <- matrix(sample(1:6, 110, replace=TRUE), ncol=11)
missVal <- 4
m[4, ] <- rep(missVal, 11)
m <- m[ rowSums((m==missVal)) != NCOL(m), ]

最后一行代码能够正常运行是因为m==missVal返回一个由逻辑值(TRUE/FALSE)组成的矩阵。 rowSumsTRUE转换为1,将FALSE转换为0,在这种情况下,当rowSums返回11时,我们知道所有列都是4

2

使用 data.table 实现内存效率。创建 is.na(x) 的解决方案会创建一个与原始数据集一样大的数据集,因此效率低下。

library(data.table)
DT <- as.data.table(m)
missing_value <- 4
missing <- as.data.table(setNames(as.list(rep(4, length(DT)), names(DT))
setkeyv(DT, names(DT))
setkey(missing, names(DT))

DT[-DT[(missing),which=T]]

这个解决方案和@JoshuaUlrich的解决方案在处理大量数据时都很快

set.seed(21)
m <- matrix(sample(1:6, 1100000, replace=TRUE), ncol=11)
missVal <- 4
missing_rows <- sample(100000, 53)
m[missing_rows, ] <- rep(missVal, 11)

DT <- as.data.table(m)
setkeyv(DT, names(DT))
missing <- setNames(as.list(rep(missVal, 11)), names(DT))

system.time({DT1 <- DT[-DT[missing,which=T]]})
## user  system elapsed 
## 0.02    0.00    0.01 
system.time({m1 <- m[ rowSums((m==missVal)) != NCOL(m), ]})
## user  system elapsed 
## 0.02    0.02    0.03 

1
使用T/F代替TRUE/FALSE时要小心,因为TF可以被重新定义。 - Joshua Ulrich

1

类似这样的代码应该可以解决问题(并且适用于矩阵和数据框):

ac<-matrix(c("4","4","4","4","4","4","4","3","3","4","4", rep("4", 11)), nrow=2, ncol=11, byrow=TRUE)

rowsToRemove<-which(apply(ac, 1, function(currow){
    all(currow=="4")
}))

现在你可以简单地执行

newac<-ac[-rowsToRemove,]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接