Rで、条件 (時に複数条件) にあうデータを取り出す方法
はじめに
"data" というデータセットから、文字列の列で条件に合うデータを、抽出する方法の覚え書きです。data の例として、R をインストールしてあれば、だれでも呼びだせる iris というアヤメの観測データの見本データを使いました。data に iris を格納して、Species が、virginica または、versicolor のデータを抜き出し、subdata に格納します。
恐らく下記の3つの方法のどれかで、ほとんどの要求に耐えられるはずです。
- 行指定を、data[ 行指定 , 列指定 ] 内の左の行指定部分に入れる (基本)
- subset 関数を使う
- dplyr パッケージの filter を使う
では、あまり、面倒なことは読みたくない方のために、いきなり結論式から書きます。
# データの読み込み
data(iris)
data <- iris
#1. 行番号を、data[ 行番号指定 , 列番号指定 ] 内の左の行番号指定部分に入れる
subdata <- data[data$Species=="virginica" | data$Species=="versicolor", ]
#2. subset 関数を使う
subdata <- subset(data, Species=="virginica" | Species=="versicolor")
#3. dplyr パッケージの filter を使う
subdata<- data %>%
dplyr::filter(Species=="virginica" | Species=="versicolor")
もう少し詳しく知りたい人は、下記を読みましょう。
上の3つの例では、良く見ると、
data$Species=="virginica" | data$Species=="versicolor"
と、いうところが、"data"の有無で表現が異りますが基本構造は共通ですね。このコードの意味するところなどを下記に順番に説明していきます。 これが、「そうだね」って感じられる方は、下記を読む必要性は低いしょう。
行と列の指定方法の基本をおさえよう
データを読み込み
まず、下記でデータを読み込みましょう。R に下のコード2行を、コピー&ペーストすれば、data に iris のデータが格納されます。# データの読み込み
data(iris)
data <- iris
行と列の指定方法基本
"data[ 行番号指定 , 列番号指定 ]" とするのが基本です。ここで、
- 「行番号指定」は、上から何番目にある行 (row 約は「行」または「並び」 <水平方向に長い梁のようなかたまり> )を表示して欲しいかを書きます
- 「列番号指定」は、左から何番目にある列 (column = 柱 <垂直方向に長い柱状のかたまり>) を表示して欲しいかを書きます
2種類の指定方法
行や列の番号を指定する方法は2つあります。以下に、順番に例示していきますので、よかったら、R に、コピー&ペーストして、どうなるか確認して下さい。">" という記号に続けて、コードを書いています。この下には、出力結果が載っていることが多いです。ここで、注意があります。 くれぐれも、">" の次のところから、コピー&ペーストして下さい。">"を入れると、動きません。
- 番号を指定する (複数の時は、c() の中に入れるなどベクトル化して入れます。長さは必要な行や列の数だけ)
- 例1. data[c(1,4,6,10),]
第1,4,6,10行目を抜き出します。列指定が空欄の場合は、R では全部の行や列が指定されます
> data[c(1,4,6,10),]
Sepal.Length Sepal.Width Petal.Length Petal.Width Species 1 5.1 3.5 1.4 0.2 setosa 4 4.6 3.1 1.5 0.2 setosa 6 5.4 3.9 1.7 0.4 setosa 10 4.9 3.1 1.5 0.1 setosa
- 例2. data[3, c(1,2)]
> > data[3, c(1,2)]
Sepal.Length Sepal.Width 3 4.7 3.2
- 例1. data[c(1,4,6,10),]
- 抜き出したい位置に、"true"、不要な部分に "false" を、行の数だけもれなく記載したブーリアン型のベクトルを入れる (複数条件の時は、こちらの方が便利です)
2番目については、後で詳しく記載します。
データ内の情報のあつめ方
データ内に、どんな情報があるかを知らないと、さすがに指定はできません。おすすめの方法は下記の順です。
- dim(data) # データの大きさを知る (垂直方向に何列、水平方向に何列かが判ります)
- データが横に長くなければ、summary(data) で概略を知る
> dim(data) [1] 150 5 > summary(data) Sepal.Length Sepal.Width Petal.Length Petal.Width Species Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100 setosa :50 1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300 versicolor:50 Median :5.800 Median :3.000 Median :4.350 Median :1.300 virginica :50 Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199 3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800 Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
summary() の結果を見ると、はじめ4つの列データは数値データで、5つ目の "Species" が文字データです。
数値データには、おおよ数値分布の目安を示してくれます。
- 最小値
- 第1四分位
- 中央値 (median)
- 平均 (mean)
- 第3四分位
- 最大値
文字列のデータには、度数 (登場回数) の多い順に、5つくらいまでの名前と度数を示してくれます。
もし、全部の列名が知りたい時は、colnames()を使います。
> colnames(data) [1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" "Species"
summary() で表示しきれない文字列データの度数を調べるには、table() が便利です。
> table(data[,5]) setosa versicolor virginica 50 50 50
これで、5番目の "Species" という名前の列 (柱) に、"setosa"、 "versicolor"、 "virginica" という3種のアヤメについて 50 個体ずつ観察されたデータで、観測項目に"Sepal.Length"、"Sepal.Width"、 "Petal.Length"、 "Petal.Width"あることを知ることができます。
"virginica" という "Species" のデータを抜き出してみよう
ここで、先程、説明を保留した、TRUE または、FALSE が、行の数だけ並ぶブーリアン型のベクトルというものが、おおいに役に立ちます。
検索条件を記載するには、演算子の使い方を知る必要があります。
演算子 の簡単な説明
"A" と "B" について、等しいのか、等しくないのかを R に尋ねて、TRUE または、FALSE で、答えてもらうことができます。
- A と B が等しければ "TRUE" と答えて欲しい時は、 "A == B" と書きます
- A と B が等しくなければ "TRUE" と答えて欲しい時は、 "A != B" と書きます
ここで、"=" が1つだと、A に B が代入されて、TRUE とも FALSE とも答えてくれません。
数字と文字列で例を上げますよ。
> 1==1 [1] TRUE > 1!=1 [1] FALSE > 2==1 [1] FALSE > 2!=1 [1] TRUE > "りんご" == "みかん" [1] FALSE > "りんご" != "みかん" [1] TRUE
数字の場合は、不等号でも TRUE または、FALSE で、答えてもらうことができます。
> 1>2 [1] FALSE > 2>1 [1] TRUE
"Species" 内の "virginica"の位置に "TRUE" が入るブーリアン型のベクトルを手に入れよう
"==" で R に尋ねれば、"Species" 内の何番目が "virginica" なのかを、TRUE または、FALSE が、行の数だけ並ぶブーリアン型のベクトルで答えてくれます。 R に尋ねる前に、"Species" のデータは、iris$Species または、iris[,5] として、"Species" のデータを抜き出しましょう。 後から見たとき、人が見たときに、理解しやすいのは、"iris$Species" という表記です。コードを書く時は、書きやすい方よりも、他人が見て判りやすい方を優先しましょう。
> iris$Species [1] setosa setosa setosa setosa setosa setosa setosa setosa [9] setosa setosa setosa setosa setosa setosa setosa setosa [17] setosa setosa setosa setosa setosa setosa setosa setosa [25] setosa setosa setosa setosa setosa setosa setosa setosa [33] setosa setosa setosa setosa setosa setosa setosa setosa [41] setosa setosa setosa setosa setosa setosa setosa setosa [49] setosa setosa versicolor versicolor versicolor versicolor versicolor versicolor [57] versicolor versicolor versicolor versicolor versicolor versicolor versicolor versicolor <中間部分は略します> [145] virginica virginica virginica virginica virginica virginica Levels: setosa versicolor virginica
このように、150個のデータが抜き出せます。 では、"Species" 内の何番目が "virginica" なのかを、"==" を使って尋ねてみましょう。
> iris$Species=="virginica" [1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [15] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [29] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [43] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [57] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [71] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [85] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE [99] FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE [113] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE [127] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE [141] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
このブリーアン型のベクトルを使って、"virginica" のデータを抜き出しまぞう。
1つの手順を踏んでから、抜き出します。
- ブリーアン型のベクトルを、Row_select に納める
- data[Row_select, ]に入れて、データを抜き出し,Subdata に格納する
- summary() で、Subdata を調べる
> Row_select <- iris$Species=="virginica" > Subdata <- data[Row_select, ] > summary(Subdata) Sepal.Length Sepal.Width Petal.Length Petal.Width Species Min. :4.900 Min. :2.200 Min. :4.500 Min. :1.400 setosa : 0 1st Qu.:6.225 1st Qu.:2.800 1st Qu.:5.100 1st Qu.:1.800 versicolor: 0 Median :6.500 Median :3.000 Median :5.550 Median :2.000 virginica :50 Mean :6.588 Mean :2.974 Mean :5.552 Mean :2.026 3rd Qu.:6.900 3rd Qu.:3.175 3rd Qu.:5.875 3rd Qu.:2.300 Max. :7.900 Max. :3.800 Max. :6.900 Max. :2.500
Subdata には、virginica 50 個体のデータだけが抜きだされました。
論理演算子を使って、Species が、virginica または、versicolor のデータを抜き出してみよう
「かつ」のとき "&" と「または」の時の "|" を上手に使うと、複数条件に合うものを抽出できるようになります。"&" と "|" に、まずは、慣れてみましょう。
> TRUE & TRUE [1] TRUE > TRUE & FALSE [1] FALSE > TRUE | TRUE [1] TRUE > TRUE | FALSE [1] TRUE > FALSE & FALSE [1] FALSE > FALSE | FALSE [1] FALSE
となります。
では、Species が、virginica または、versicolor のデータを抜き出してみましょう。「または」ですから、"|"を使いますね。
- Species が、virginica のもの、Species が versicolor であるブリーアン型のベクトルを2つ手に入れる
- 「または」 の理論演算子 "|" を使って2つのベクトルを1つにする
- data から1つにしたベクトルで抜き出す
#Species が、virginica > Row_virginica <- iris$Species=="virginica" # Species が versicolor > Row_versicolor <- iris$Species=="versicolor" # 演算子で結合 > Row_select <- Row_virginica | Row_versicolor # 抜き出します > Subdata <- data[Row_select,] # summary() で調べてみよう > summary(Subdata) Sepal.Length Sepal.Width Petal.Length Petal.Width Species Min. :4.900 Min. :2.000 Min. :3.000 Min. :1.000 setosa : 0 1st Qu.:5.800 1st Qu.:2.700 1st Qu.:4.375 1st Qu.:1.300 versicolor:50 Median :6.300 Median :2.900 Median :4.900 Median :1.600 virginica :50 Mean :6.262 Mean :2.872 Mean :4.906 Mean :1.676 3rd Qu.:6.700 3rd Qu.:3.025 3rd Qu.:5.525 3rd Qu.:2.000 Max. :7.900 Max. :3.800 Max. :6.900 Max. :2.500
以上でできました。data[Row_select, c(2,3,5)] としたら、2列目、3列目、5列目だけ抜き出してくれます。
subset 関数について
subset(data, 検索条件, select = 抽出する列名)
「select = 抽出する列名」は記載しなければ、全部の行を対象にしてくれます。
subdata <- subset(iris, Species=="virginica" | Species=="versicolor")
で抜き出しができます。下記でも大丈夫です。
> Row_virginica <- iris$Species=="virginica" > Row_versicolor <- iris$Species=="versicolor" > Row_select <- Row_virginica | Row_versicolor > Subdata <- subset(iris, Row_select)
subset(iris, Row_select, select=c(2,3,5)) と、select のオプションを入れれば、2列目、3列目、5列目だけ抜き出してくれます。
数字との組み合わせ
subdata <- iris[iris$Species=="virginica" | iris$Species=="versicolor" & iris$Sepal.Length>6, ]
など、としたら良いです。数字については、普通は "&" で継ぐことになります。 A | B & C の順に書いた時は、 (A | B) & C という順の計算になります。
オマケで、計算速度比較
> prt <- proc.time() > subdata <- data[data$Species=="virginica" | data$Species=="versicolor",] > proc.time()-prt ユーザ システム 経過 0.027 0.002 0.025 > > prt <- proc.time() > subdata <- subset(data, Species=="virginica" | Species=="versicolor") > proc.time()-prt ユーザ システム 経過 0.007 0.001 0.007 > > library(dplyr) > prt <- proc.time() > subdata<- data %>% + dplyr::filter(Species=="virginica" | Species=="versicolor") > proc.time()-prt ユーザ システム 経過 0.014 0.001 0.014
1万行くらいのデータで見てみたら、どれも似たような速さでした。
dplyr は、抜き出すだけではなく、並び換えたり、集計を加えることもできて多機能で、さらに可読性が良いことが美点ですね。 "%>%" と "dplyr::" という書式にびっくりしますが、この2つは、単なるお作法と割り切れば、実はこわいものでもないですね。dplyr は、抜き出すだけだと、ちょっと、良さが出ない印象です。
ちなみに、文字列に限れば、grep するのが最速ではないでしょうか。これは、たぶん、grep が行番号のベクトルを返すことが理由でしょう。