もともとは別のことをしようと思ったのですが、1トピックに絞ります。
データフレームの列名をある程度ざっくりと選びたい。
select_atとかでも良いのかもしれませんが、select_ifは条件を指定して選ぶことが出来るので便利ですね。
たとえばこんな感じに。
iris %>% select_if(str_detect(colnames(.), "Petal")) %>% head #> Petal.Length Petal.Width #> 1 1.4 0.2 #> 2 1.4 0.2 #> 3 1.3 0.2 #> 4 1.5 0.2 #> 5 1.4 0.2 #> 6 1.7 0.4
これについては、この書き方でも出来る。
iris %>% select(contains("Sepal")) %>% head() #> Sepal.Length Sepal.Width #> 1 5.1 3.5 #> 2 4.9 3.0 #> 3 4.7 3.2 #> 4 4.6 3.1 #> 5 5.0 3.6 #> 6 5.4 3.9
後者については安定のyutannihilationさんからのアドバイス
ちがう、iris %>% select(contains("S"))でした。ボケてるな...
— Hiroaki Yutani (@yutannihilation) 2017年12月24日
をいただきました。
このとき、列名に複数の条件を指定する場合は前者の書き方を使い、str_detectのpatternの方に書くと出来て、こんな感じになります。
iris %>% select_if(str_detect(colnames(.), "(Petal)|(Sepal)")) %>% head #> Sepal.Length Sepal.Width Petal.Length Petal.Width #> 1 5.1 3.5 1.4 0.2 #> 2 4.9 3.0 1.4 0.2 #> 3 4.7 3.2 1.3 0.2 #> 4 4.6 3.1 1.5 0.2 #> 5 5.0 3.6 1.4 0.2 #> 6 5.4 3.9 1.7 0.4
後者の方法では複数指定はたぶんできない...
列が大量にあるけど、特定の文字列を含むことがわかっていて、それが複数のパタンある場合に使える(使った)のですが、そんなに需要はないのかも。 他にも良い方法はありそうですが、「条件を満たしたら選択(select_if)する、条件は列名について次のパタンを見つけたとき」と、自分にはわかりやすいので良いかな…
select_ifの挙動
この前後でちょっとハマってしまって、またユタ兄さんに助けていただきました。
*_if()に指定できるのは、(1)関数か(2)論理値型ベクトルです。(1)の場合はその関数が各列の中身のベクトルに適用され、結果がTRUEになるものだけが選択されます。select_if(is.numeric)みたいな感じです。str_detect()は(2)のパターンですね。
— Hiroaki Yutani (@yutannihilation) 2017年12月24日
論理型のベクトルの場合はそのまま列が選択される。下記の例だとselect(c(1,4))としたときと同じ結果になる
iris %>% select_if(c(T,F,F,T,F)) %>% head #> Sepal.Length Petal.Width #> 1 5.1 0.2 #> 2 4.9 0.2 #> 3 4.7 0.2 #> 4 4.6 0.2 #> 5 5.0 0.2 #> 6 5.4 0.4
一方、上の方に書いたようにfunctionで与えると、各列をベクトルとして与えます。 これは下記のようにして確かめることが出来ます(listではないことの確認。data.frameでも同様
iris %>% select_if(function(df){is.list(df)}) NA iris %>% select_if(function(df){is.vector(df)}) %>% head #> Sepal.Length Sepal.Width Petal.Length Petal.Width #> 1 5.1 3.5 1.4 0.2 #> 2 4.9 3.0 1.4 0.2 #> 3 4.7 3.2 1.3 0.2 #> 4 4.6 3.1 1.5 0.2 #> 5 5.0 3.6 1.4 0.2 #> 6 5.4 3.9 1.7 0.4```
しかし、reprex使うと1つめはNAが返って?きますね…。コンソール上だと「0 列 150 行のデータフレーム」と返ってきますが。それぞれ環境が異なるので表示が違っても(゚ε゚)キニシナイ!!
しかし、functionは↓のように、typeofだとclosureって返ってきてやや混乱しますね(classもちゃんとfunctionって返すのか…知らなかった)
str(function(){}) #> function () #> - attr(*, "srcref")=Class 'srcref' atomic [1:8] 17 5 17 16 5 16 17 17 #> .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x00000000160567e0> typeof(function(){}) #> [1] "closure" mode(function(){}) #> [1] "function" class(function(){}) #> [1] "function" is.function(function(){}) #> [1] TRUE
ということで、ちゃんとマニュアルに目を通しましょう…というお話でした(そうだっけ?)
Enjoy!!
追記
その後、select+matchesでもいけますよ!ということでアドバイスいただきました。
@niszet0 すいません、今更ですがこれ複数指定というのを勘違いしてました。正規表現を使うにはmatches()というやつがあります。参考までに。 https://t.co/Cl4hWwbdzD
— Hiroaki Yutani (@yutannihilation) 2017年12月29日
やってみた。
iris %>% select(matches("(Petal)|(Sepal)")) %>% head #> Sepal.Length Sepal.Width Petal.Length Petal.Width #> 1 5.1 3.5 1.4 0.2 #> 2 4.9 3.0 1.4 0.2 #> 3 4.7 3.2 1.3 0.2 #> 4 4.6 3.1 1.5 0.2 #> 5 5.0 3.6 1.4 0.2 #> 6 5.4 3.9 1.7 0.4
こっちの方が簡単ですね…。selectだと、列の番号を受け取れればそれを選択できる。select_ifは対応する列のT/Fで選択する/しないをわける、と。
また、こちらの記事も参考に、とのことでした。
Enjoy!!