`[`が `subset`より優れているのはなぜですか?


400

data.frameをフィルター処理する必要がある場合、つまり特定の条件を満たす行を抽出する場合は、次のsubset関数を使用します。

subset(airquality, Month == 8 & Temp > 90)

[関数ではなく:

airquality[airquality$Month == 8 & airquality$Temp > 90, ]

私の好みには主に2つの理由があります。

  1. 私はコードが左から右に、よりよく読みます。Rについて何も知らない人でも、subset上記のステートメントが何をしているのかわかるでしょう。

  2. 式では列を変数として参照selectできるため、いくつかのキーストロークを節約できます。上記の例では、でairquality一度入力するだけでsubset、で3回入力する必要がありました[

それで、私は幸福に生きsubsetていました。短くて読みやすいのでどこでも使用し、その美しさを仲間のRプログラマーにさえ主張していました。しかし、昨日私の世界はバラバラになりました。subsetドキュメントを読んでいると、このセクションに気づきました。

警告

これは、インタラクティブに使用することを目的とした便利な関数です。プログラミングには、[のような標準サブセット関数を使用することをお勧めします。特に、引数サブセットの非標準評価は予期しない結果をもたらす可能性があります。

誰かが著者の意味を明確にするのを手伝ってくれませんか?

まず、「インタラクティブに使用する」とはどういう意味ですか?バッチモードで実行されるスクリプトとは対照的に、対話型セッションが何であるかはわかっていますが、どのような違いがあるのか​​わかりません。

それでは、「引数サブセットの非標準の評価」と、なぜそれが危険なのか、例を挙げて説明していただけますか?


14
使用する方が少し少ない(ただしサブセットよりも少ない)with(airquality, airquality[Month == 8 & Temp > 90, ])
Tyler Rinker '25年


9
代わりにdata.tableを試してください。デフォルトの構文はairquality [Month == 8&Temp> 90、]のようで、非常に読みやすく、はるかに高速です。
StianHåklev2013

3
OK。したがって、サブセットが使用に適さない場合-[vs. dplyr :: filter()はどうですか?
userJT 2015

4
疑問に思う方のためdplyr::filterに、同じ問題があります。つまり、環境にその名前の変数がある場合、データフレーム内の変数の代わりにその名前が使用されます。混乱を招くデバッグになります!
デリート2017年

回答:


241

この質問は、@ Jamesのコメントでよく回答されており、ハドリーウィッカムによる危険subset(およびそのような機能)についての優れた説明を示しています[ここ]。読んでください!

これはやや長い読みですので、「何がうまくいかないのか」という質問に最も直接対処するHadleyが使用する例をここに記録しておくと役に立ちます。

Hadleyは次の例を提案します。次の関数を使用してデータフレームをサブセット化して並べ替えたいとします。

scramble <- function(x) x[sample(nrow(x)), ]

subscramble <- function(x, condition) {
  scramble(subset(x, condition))
}

subscramble(mtcars, cyl == 4)

これはエラーを返します:

eval(expr、envir、enclos)のエラー:オブジェクト 'cyl'が見つかりません

Rが 'cyl'と呼ばれるオブジェクトの場所を「認識」しなくなったためです。彼はまた、地球環境に「cyl」と呼ばれるオブジェクトが偶然存在する場合に発生する可能性がある本当に奇妙なことを指摘しています。

cyl <- 4
subscramble(mtcars, cyl == 4)

cyl <- sample(10, 100, rep = T)
subscramble(mtcars, cyl == 4)

(それらを実行して、自分の目で確かめてください。かなりおかしいです。)


2
説明のために初心者向けの質問がありますか?subset(mtcars, cyl == 4)(トップレベルで)書くとき、Rはcylをどこで探すのですか?にmtcars渡されるオブジェクトsubset()を調べたcyl場合scramble、それmtcarsがまだ渡されているので、別の関数内にある場合でもそれを見つけることができないのではないでしょうか。私の質問が意味をなさない場合は、Rがを見つけられない理由をさらに詳しく説明してくださいcyl。ありがとう!
ハイゼンベルク

4
@Anh Inside subset.data.frameでは、その時点で評価しようとしているのはただconditionです。それはには存在しませんmtcars。したがって、がとして正しく評価されることを確認するためにsubset.data.frame使用enclos = parent.frame()します。しかし、それから囲んでいるフレームに戻り、Rが検索すると、の内部は見えなくなりました。を使用しない場合、などはまったく機能しません。conditioncyl == 4cylmtcarsenclossubset(mtcars,cyl == a)
joran 2013年

誰かがサブセット()が舞台裏でより速くより安全な[、]メソッドを実装しない理由を知っていますか?
ビョークは、2017

1
@MikePalmiceあります。の最後の行はsubset.data.frameですx[r, vars, drop = drop]。問題は、引用符で囲まれていないから取得する方法であるsubsetselectあなたが正当に渡すことができることを何かに引数[.data.frame
joran

@joran、ありがとう。代わりにdplyrのフィルターを使用するかどうかについてどう思いますか[]
ビョーク

30

また[高速です:

require(microbenchmark)        
microbenchmark(subset(airquality, Month == 8 & Temp > 90),airquality[airquality$Month == 8 & airquality$Temp > 90,])
    Unit: microseconds
                                                           expr     min       lq   median       uq     max neval
                     subset(airquality, Month == 8 & Temp > 90) 301.994 312.1565 317.3600 349.4170 500.903   100
     airquality[airquality$Month == 8 & airquality$Temp > 90, ] 234.807 239.3125 244.2715 271.7885 340.058   100

36
はいといいえ。あなたが見ている時差は二つの原因によると思います。1)小さい(<100マイクロ秒)オーバーヘッド、および2)フィルターがと評価される行を削除するのsubset[は異なりNAます。これを行うと、あなたは彼らが両方比べ速いと「かなり」であることがわかります:x <- do.call(rbind, rep(list(airquality), 100)); microbenchmark(subset(x, Month == 8 & Temp > 90),{ i <- x$Month == 8 & x$Temp > 90; x[!is.na(i) & i ,] })
flodel
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.