2012年6月15日金曜日
for()ループを入れ子にして検索するより、Rならではの方法で
IDと数値をもつ表があり、それとは別にIDのリストがあるとする。そのとき、リスト中のIDに対応する数値を表から抽出するにはどうしたらいいだろうか。
Rを使う。
for()ループでIDリストを1つずつ取り出し、そのループの中で更にfor()ループを使って表を1行ずつ取り出し、対応するIDをif()で探すという方法が思い浮かぶ。for()ループを入れ子構造にするやり方だ。方法を下に示す。
この入れ子構造でやってみるとものすごく遅い。2つ目のfor()ループは表の行数マイナス1行分も無駄に動いているわけだから、遅いのも頷ける。でも、perlだったらもっと速くに結果がでるような気がする。どうやらRはループが苦手らしい。
作業効率がとても悪いので、for()ループをひとつ減らして同じ結果を得る方法を考えた。if()で条件検討をせず、セルが一致する行をそのままRっぽく拾う。方法を下に示す。
ここに示す小さなデータではスピードの違いを実感できないが、数千行の表の中から数百のリストに合致する行を得ようとすれば、その違いは雲泥の差。前者ならかけっぱなしで散歩にでも行きたくなるが、後者ならあくびをしている間に終了する。
とりあえず、説明用にデータを用意する。
データフレーム(df.1)を用意する。
id1 <- c("A","B","C","D","E","F")
value1 <- rnorm(6,mean=3,sd=1)
df1 <- data.frame(id1,value1)
> df1
id1 value1
1 A 2.484163
2 B 1.539250
3 C 2.773143
4 D 1.041669
5 E 2.409677
6 F 2.532448
IDリスト(id2)を用意する。
id2 <- c("B","D","E")
> id2
[1] "B" "D" "E"
入れ子構造のやり方。
forループを2つ重ねて検索する。
found1 <- df1[0,]
for (i in 1:length(id2)){
for (j in 1:nrow(df1)){
if (id2[i]==df1[j,1]){
hit1 <- df1[j,]
found1 <- rbind(found1,hit1)
}
}
}
> found1
id1 value1
2 B 1.539250
4 D 1.041669
5 E 2.409677
Rの強みを活かすやり方。
forループをひとつだけにする。
found2 <- df1[0,]
for(x in 1:length(id2)){
hit2 <- df1[df1[,1]==id2[x],]
found2 <- rbind(found2,hit2)
}
> found2
id1 value1
2 B 1.539250
4 D 1.041669
5 E 2.409677
登録:
コメントの投稿 (Atom)
0 件のコメント:
コメントを投稿