NAのみを含む列を削除するにはどうすればよいですか?


83

すべてのNA値を持ついくつかの列を含むdata.frameがありますが、data.frameからそれらを削除するにはどうすればよいですか。

機能を使用できますか

na.omit(...) 

いくつかの追加の引数を指定しますか?


1
こんにちは!投稿を再現可能にしてください。これを行う方法について、再現性のある優れた例を作成する方法についての投稿を読んでください。ありがとうございました。
アルン2013

この投稿は役に立ちますか?stackoverflow.com/questions/4862178/…–
アルン

投稿できますhead(data)か?対応する列または行を削除しますか?
ニシャント2013

@ e4e5f4対応する列を削除したい(削除したい列の値はすべてNAです)
Lorenzo Rigamonti 2013

回答:


123

それを行う1つの方法:

df[, colSums(is.na(df)) != nrow(df)]

列内のNAの数が行の数と等しい場合は、完全にNAである必要があります。

または同様に

df[colSums(!is.na(df)) > 0]

1
NAのしきい値を超える列を削除するにはどうすればよいですか?またはパーセンテージ(50%以上としましょう)?
discipulus 2015年

2
@lovedynastyコメントを投稿してからまだ投稿していない場合は、別の質問を送信するのがおそらく最善です。しかし、とにかく、あなたはいつでも次のようなことをすることができます。df[, colSums(is.na(df)) < nrow(df) * 0.5]つまり、少なくとも50%が空白でない列のみを保持します。
MadScone 2015

2
df[, colSums(is.na(df)) != nrow(df) - 1]対角線は常に1
Boern

9
これは、dplyr(バージョン0.5.0)のselect_if関数でも使用できます。 df %>% select_if(colSums(!is.na(.)) > 0)
Stefan Avey 2016年

@MadScone df [、colSums(is.na(df))!= nrow(df)]の場合、「、」で構文エラーが発生し、「!」で構文エラーが発生します。df [colSums(!is.na(df))> 0]。私は何かが足りないのですか
Aravind S

52

これがdplyrソリューションです:

df %>% select_if(~sum(!is.na(.)) > 0)

4
〜15k行と〜5k列では、これは本当に永遠にかかります。
EngrStudent 2017

@EngrStudent受け入れられた回答の解決策の方が速かったですか?
ジョニー

何年も経ちました。覚えていません。DJVには以下の素晴らしいタイミングポストがあります。
EngrStudent


24

ALLが含まれるのみを削除し、が含まれる行がいくつかある列を残したいようです。私はこれを行います(しかし、効率的なベクトル化されたソリューションがあると確信しています: NANA

#set seed for reproducibility
set.seed <- 103
df <- data.frame( id = 1:10 , nas = rep( NA , 10 ) , vals = sample( c( 1:3 , NA ) , 10 , repl = TRUE ) )
df
#      id nas vals
#   1   1  NA   NA
#   2   2  NA    2
#   3   3  NA    1
#   4   4  NA    2
#   5   5  NA    2
#   6   6  NA    3
#   7   7  NA    2
#   8   8  NA    3
#   9   9  NA    3
#   10 10  NA    2

#Use this command to remove columns that are entirely NA values, it will elave columns where only some vlaues are NA
df[ , ! apply( df , 2 , function(x) all(is.na(x)) ) ]
#      id vals
#   1   1   NA
#   2   2    2
#   3   3    1
#   4   4    2
#   5   5    2
#   6   6    3
#   7   7    2
#   8   8    3
#   9   9    3
#   10 10    2

NA値を持つ列を削除したい場合は、all上記のコマンドをに変更するだけanyです。


data.frameには2つのタイプの列があります。1つはすべての値が数値で、もう1つはすべての値がNAです
Lorenzo Rigamonti 2013

したがって、これは機能します。すべての値がであった列のみを削除しますNA
サイモンオハンロン2013

1
良い解決策。apply(is.na(df), 1, all)少しすっきりしていて、一度に1行でis.na()dfなくすべてで使用されるという理由だけで、私はそうします(少し速く表示します)。
MadScone 2013

@MadSconeの良いヒント-きれいに見えます。ただし、行ではなく列全体に適用する必要があります。
サイモンオハンロン2013

@MadScone編集はコメントで5分後にロックされます。心配しないで、大したことじゃない!! :-)
Simon O'Hanlon 2013

19

直感的なスクリプト:dplyr::select_if(~!all(is.na(.)))。文字通り、すべての要素が欠落していない列のみを保持します。(すべての要素が欠落している列を削除するため)。

> df <- data.frame( id = 1:10 , nas = rep( NA , 10 ) , vals = sample( c( 1:3 , NA ) , 10 , repl = TRUE ) )

> df %>% glimpse()
Observations: 10
Variables: 3
$ id   <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
$ nas  <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA
$ vals <int> NA, 1, 1, NA, 1, 1, 1, 2, 3, NA

> df %>% select_if(~!all(is.na(.))) 
   id vals
1   1   NA
2   2    1
3   3    1
4   4   NA
5   5    1
6   6    1
7   7    1
8   8    2
9   9    3
10 10   NA

17

別のオプション Filter

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

注:@ SimonO'Hanlonの投稿からのデータ。


5

パフォーマンスは私にとって非常に重要だったので、上記のすべての機能のベンチマークを行いました。

注:@ SimonO'Hanlonの投稿からのデータ。サイズが10ではなく15000の場合のみ。

library(tidyverse)
library(microbenchmark)

set.seed(123)
df <- data.frame(id = 1:15000,
                 nas = rep(NA, 15000), 
                 vals = sample(c(1:3, NA), 15000,
                               repl = TRUE))
df

MadSconeF1 <- function(x) x[, colSums(is.na(x)) != nrow(x)]

MadSconeF2 <- function(x) x[colSums(!is.na(x)) > 0]

BradCannell <- function(x) x %>% select_if(~sum(!is.na(.)) > 0)

SimonOHanlon <- function(x) x[ , !apply(x, 2 ,function(y) all(is.na(y)))]

jsta <- function(x) janitor::remove_empty(x)

SiboJiang <- function(x) x %>% dplyr::select_if(~!all(is.na(.)))

akrun <- function(x) Filter(function(y) !all(is.na(y)), x)

mbm <- microbenchmark(
  "MadSconeF1" = {MadSconeF1(df)},
  "MadSconeF2" = {MadSconeF2(df)},
  "BradCannell" = {BradCannell(df)},
  "SimonOHanlon" = {SimonOHanlon(df)},
  "SiboJiang" = {SiboJiang(df)},
  "jsta" = {jsta(df)}, 
  "akrun" = {akrun(df)},
  times = 1000)

mbm

結果:

Unit: microseconds
         expr    min      lq      mean  median      uq      max neval  cld
   MadSconeF1  154.5  178.35  257.9396  196.05  219.25   5001.0  1000 a   
   MadSconeF2  180.4  209.75  281.2541  226.40  251.05   6322.1  1000 a   
  BradCannell 2579.4 2884.90 3330.3700 3059.45 3379.30  33667.3  1000    d
 SimonOHanlon  511.0  565.00  943.3089  586.45  623.65 210338.4  1000  b  
    SiboJiang 2558.1 2853.05 3377.6702 3010.30 3310.00  89718.0  1000    d
         jsta 1544.8 1652.45 2031.5065 1706.05 1872.65  11594.9  1000   c 
        akrun   93.8  111.60  139.9482  121.90  135.45   3851.2  1000 a


autoplot(mbm)

ここに画像の説明を入力してください

mbm %>% 
  tbl_df() %>%
  ggplot(aes(sample = time)) + 
  stat_qq() + 
  stat_qq_line() +
  facet_wrap(~expr, scales = "free")

ここに画像の説明を入力してください


最初の反復はJITコンパイルされている場合があるため、非常に貧弱で、あまり特徴的ではありません。大きなサンプルサイズが分布の右裾にどのように作用するかは興味深いと思います。これは良い仕事です。
EngrStudent

もう一度実行しましたが、プロットを変更したかどうかわかりませんでした。配布に関しては、確かに。時間があるときに、おそらく異なるサンプルサイズを比較する必要があります。
DJV

1
「akrun」などのトレンドの1つをqqplot(ggplot2.tidyverse.org/reference/geom_qq.html)すると、残りの分布とは大きく異なるポイントが1つあるに違いありません。残りは、繰り返し実行した場合の所要時間を表しますが、1回実行した場合の結果を表します。古いことわざがあります:あなたは20年の経験を持つことができます、またはあなたは20回だけ1年の価値のある経験を持つことができます。
EngrStudent

非常に素晴らしい!いくつかのサンプルが極端な尾にあることに驚いています。どうしてこんなに高額なのかしら。JITは1または2かもしれませんが、20ではありません。状態?割り込み?その他?更新していただきありがとうございます。
EngrStudent

どういたしまして、ご意見ありがとうございます。わからない、私は実際にそれを「自由に」実行することを許可した。
DJV
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.