从数据框中删除某些值为NA的列

45

我有一个数据框,其中一些值为NA。我想把这些列删除。

我的数据框长这样

    v1   v2 
1    1   NA 
2    1    1 
3    2    2 
4    1    1 
5    2    2 
6    1   NA

我尝试估算列均值并选择列均值不等于NA的列。我尝试了这个语句,但它没有起作用。

data=subset(Itun, select=c(is.na(colMeans(Itun))))

我遇到了一个错误,

错误:'x' 必须是至少二维数组

有人可以帮我解决吗?


请提供您想要的结果示例。同时,提供一个完全可重现的示例将非常有帮助。 - BenBarnes
8个回答

71

数据:

Itun <- data.frame(v1 = c(1,1,2,1,2,1), v2 = c(NA, 1, 2, 1, 2, NA)) 

这将删除所有至少包含一个NA的列:

Itun[ , colSums(is.na(Itun)) == 0]

另一种方法是使用apply:

Itun[ , apply(Itun, 2, function(x) !any(is.na(x)))]

是的。但他从未提到过行,并使用了 subset(..., select=...),所以我认为他想要提取某些列的所有行。 - Backlin
@SvenHohenstein:非常抱歉我的措辞不够清晰。我想从数据框中提取没有缺失值的列。 - TTT
这个返回的不是一个逻辑数组吗,而且没有对数据进行子集处理吗? - simone
应该是 Itun[ , colSums(is.na(Itun)) == 0, with = FALSE] 吗? - simone
@simone,“Itun”是一个“data.frame”,而不是一个“data.table”。 - Sven Hohenstein
显示剩余3条评论

47

以下是使用 dplyr 函数的 select_if() 的一种方便方法。结合 not (!)、any()is.na(),这相当于选取所有不包含任何 NA 值的列。

library(dplyr)
Itun %>%
    select_if(~ !any(is.na(.)))

我想知道您是否可以同时提取已删除列的列名。这可能吗? - Kots
2
我会将其拆分为两个操作。使用 Itun %>% select_if(~ any(is.na(.))) %>% names()。然后使用上述代码在第二个操作中删除列。 - Matt Dancho
很棒的解决方案。对于那些只有NAs的列应该被删除的情况,您可以使用select_if(~ !all(is.na(.)) - JdP
这个解决方案很好,但是非常慢。@Sven-hohenstein的Itun[ , colSums(is.na(Itun)) == 0]要快得多。 - Matthias Munz
如果我想要包含具有NA/NULL值的列,它会返回什么?当我运行没有!的相反操作时,它返回了一堆不含NA的列;虽然带有NA的列也与它们一起返回。 - stucash

17

或者,可以使用 select(where(~FUNCTION))

library(dplyr)

(df <- data.frame(x = letters[1:5], y = NA, z = c(1:4, NA)))
#>   x  y  z
#> 1 a NA  1
#> 2 b NA  2
#> 3 c NA  3
#> 4 d NA  4
#> 5 e NA NA

# Remove columns where all values are NA
df %>% 
  select(where(~!all(is.na(.))))
#>   x  z
#> 1 a  1
#> 2 b  2
#> 3 c  3
#> 4 d  4
#> 5 e NA
  
# Remove columns with at least one NA  
df %>% 
  select(where(~!any(is.na(.))))
#>   x
#> 1 a
#> 2 b
#> 3 c
#> 4 d
#> 5 e

14

您可以使用两次转置:

newdf <- t(na.omit(t(df)))

6
data[,!apply(is.na(data), 2, any)]

data.frame版本不应该与matrix版本相同吗,只是没有第一个逗号吗?按照您的代码,我会得到一个错误(“未定义选择的列”)。 - A5C1D2H2I1M1N2O1R2T1
1
然而,apply 在应用函数之前会将输入转换为矩阵,因此我更喜欢在数据框上使用 sapplylapply。然而,is.na 也是如此,所以在这种情况下,输入已经是一个矩阵,我的第一个示例实际上是不正确的!也许在概念上更好的解决方案是 sapply(data, function(x) !any(is.na(x))),但这真的是无关紧要的。 - Backlin

2

使用包的另一种选择是利用


最初的回答

Filter(function(x) !any(is.na(x)), Itun)

使用 data.table 会稍微麻烦一些。最初的回答。
setDT(Itun)[,.SD,.SDcols=setdiff((1:ncol(Itun)),
                                which(colSums(is.na(Itun))>0))]

2
apply函数相关的基本R方法是
Itun[!unlist(vapply(Itun, anyNA, logical(1)))]
  v1
1  1
2  1
3  2
4  1
5  2
6  1

这里使用vapply 是因为我们正在操作列表,而apply 不会将对象强制转换为矩阵。此外,由于我们知道输出将是长度为1的逻辑向量,因此可以将其输入vapply,从而可能获得一些速度提升。出于同样的原因,我使用了anyNA 而不是any(is.na())


0

你也可以尝试:

df <- df[,colSums(is.na(df))<nrow(df)]

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