すべての値がNAであるデータフレームから列を削除します


149

私は、データフレームとのトラブルを抱えていると、本当にその問題を自分で解決できませんでした:データフレームは、任意の持っている列などのプロパティをし、各行は 1つのを表すデータセットを

問題はすべての行の値がNA である列を取り除く
方法です。

回答:


155

これを試して:

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

3
これにより、古いオブジェクトのサイズのオブジェクトが作成されます。これは、ラージオブジェクトのメモリの問題です。関数を使用してサイズを小さくすることをお勧めします。Filterを使用するかdata.tableを使用すると、メモリの使用量を削減できます。
mtelesha 2015

3
これは、非数値列では機能しないようです。
バーバモア

列名が重複している場合、列名を変更します
Peter.k

97

これまでに提供された2つのアプローチは、(他のメモリの問題の中で)が作成する大きなデータセットで失敗しますis.na(df)。これは、と同じサイズのオブジェクトになりますdf

より多くのメモリと時間効率の良い2つのアプローチを次に示します

を使用したアプローチ Filter

Filter(function(x)!all(is.na(x)), df)

およびdata.tableを使用したアプローチ(一般的な時間とメモリの効率のため)

library(data.table)
DT <- as.data.table(df)
DT[,which(unlist(lapply(DT, function(x)!all(is.na(x))))),with=F]

大きなデータを使用した例(30列、1e6行)

big_data <- replicate(10, data.frame(rep(NA, 1e6), sample(c(1:8,NA),1e6,T), sample(250,1e6,T)),simplify=F)
bd <- do.call(data.frame,big_data)
names(bd) <- paste0('X',seq_len(30))
DT <- as.data.table(bd)

system.time({df1 <- bd[,colSums(is.na(bd) < nrow(bd))]})
# error -- can't allocate vector of size ...
system.time({df2 <- bd[, !apply(is.na(bd), 2, all)]})
# error -- can't allocate vector of size ...
system.time({df3 <- Filter(function(x)!all(is.na(x)), bd)})
## user  system elapsed 
## 0.26    0.03    0.29 
system.time({DT1 <- DT[,which(unlist(lapply(DT, function(x)!all(is.na(x))))),with=F]})
## user  system elapsed 
## 0.14    0.03    0.18 

6
非常に素晴らしい。data.frameただし、でも同じことができます。ここには本当に必要なものは何もありませんdata.table。キーはです。これlapplyにより、によって行われるオブジェクト全体のコピーが回避されis.na(df)ます。それを指摘するための+10。
Matt Dowle 2012

1
data.frameでそれをどのように行いますか?@ matt-dowle
s_a

8
@s_a、 bd1 <- bd[, unlist(lapply(bd, function(x), !all(is.na(x))))]
mnel 2014年

6
@mnel私はあなたが,後を削除する必要があると思いますfunction(x)-例btwのおかげで
Thieme Hennis

1
:=またはset()を使用すると、より速く実行できますか?
skan

49

dplyr今持っているselect_ifここで役に立つかもしれ動詞:

library(dplyr)
temp <- data.frame(x = 1:5, y = c(1,2,NA,4, 5), z = rep(NA, 5))
not_all_na <- function(x) any(!is.na(x))
not_any_na <- function(x) all(!is.na(x))

> temp
  x  y  z
1 1  1 NA
2 2  2 NA
3 3 NA NA
4 4  4 NA
5 5  5 NA

> temp %>% select_if(not_all_na)
  x  y
1 1  1
2 2  2
3 3 NA
4 4  4
5 5  5

> temp %>% select_if(not_any_na)
  x
1 1
2 2
3 3
4 4
5 5

dplyr解決策を探してここに来ました。がっかりしなかった。ありがとう!
AndrewBrēza19年

これには、すべてではないがほとんどの値が欠落している変数も削除されるという問題があることがわかりました
MBorg

15

別の方法は、apply()関数を使用することです。

data.frameがある場合

df <- data.frame (var1 = c(1:7,NA),
                  var2 = c(1,2,1,3,4,NA,NA,9),
                  var3 = c(NA)
                  )

次に、を使用apply()して、どの列が条件を満たすかを確認できます。そのため、applyアプローチを使用するだけで、Musaの回答と同じサブセットを簡単に実行できます。

> !apply (is.na(df), 2, all)
 var1  var2  var3 
 TRUE  TRUE FALSE 

> df[, !apply(is.na(df), 2, all)]
  var1 var2
1    1    1
2    2    2
3    3    1
4    4    3
5    5    4
6    6   NA
7    7   NA
8   NA    9

3
colSum()ソリューションがより多くの作業を行っているように見えるので、これはより高速になると予想していました。しかし、私のテストセット(前に1614変数の213 obs。、その後に1377変数)では、正確に3倍長くかかります。(ただし、興味深いアプローチの場合は+1。)
Darren Cook

10

ゲームに遅れますが、janitorパッケージを使用することもできます。この関数は、すべてNAである列を削除し、すべてNAである行を削除するように変更できます。

df <- janitor::remove_empty(df, which = "cols")



4

受け入れられた回答は、非数値列では機能しません。この答え、次のように異なるデータ型を含む列で動作します

Filter(function(x) !all(is.na(x)), df)

他の誰かがあなたの4年前にこのスレッドで同じ回答をすでに投稿しています...以下のmnelの回答を参照してください。
André.B

2

purrrパッケージの別のオプション:

library(dplyr)

df <- data.frame(a = NA,
                 b = seq(1:5), 
                 c = c(rep(1, 4), NA))

df %>% purrr::discard(~all(is.na(.)))
df %>% purrr::keep(~!all(is.na(.)))

1

これもお役に立てば幸いです。単一のコマンドにすることもできますが、2つのコマンドに分割すると読みやすくなります。以下の命令で関数を作って、電光石火で高速に動作しました。

naColsRemoval = function (DataTable) { na.cols = DataTable [ , .( which ( apply ( is.na ( .SD ) , 2 , all ) ) )] DataTable [ , unlist (na.cols) := NULL , with = F] }

.SDでは、必要に応じて検証をテーブルの一部に制限できますが、テーブル全体が次のようになります。


1

便利なbase RオプションはcolMeans()次のとおりです。

df[, colMeans(is.na(df)) != 1]

0

Janitorパッケージを使用できます remove_empty

library(janitor)

df %>%
  remove_empty(c("rows", "cols")) #select either row or cols or both

また、別のdplyrアプローチ

 library(dplyr) 
 df %>% select_if(~all(!is.na(.)))

または

df %>% select_if(colSums(!is.na(.)) == nrow(df))

これは、特定の数の欠損値を持つ列のみを除外/保持する場合にも役立ちます。例:

 df %>% select_if(colSums(!is.na(.))>500)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.