@miya-t

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

R言語でのvlookup処理

解決したいこと

Rの初学者で、いままでエクセルで処理していたことを少しずつ覚えながら、Rで行っています。

R言語で、excelのvlookupと同様の処理を行いたいです。

ループを使って処理をさせることはできるのですが、データ量が大きい時は、かなりの時間を要します。

なので、この処理だけexcelにさせていたりしています。
R上で素早くできるようになると効率的です

二つのデータフレーム、df1,df2
IDが一致していたら、df2のday(日付)を、df1のdayに代入します。
二つのデータフレームは共に複数列のデータフレームです。
df1にday列を追加する感じの処理になります。

発生している問題・エラー

エラーは発生していません。時間がかかるだけです。

該当するソースコード

for (i in 1:nrow(df1)) {
  for (j in 1:nrow(df2)) {
    if (df1$ID[i] == df2$ID[j]) {
      df1$day[i] <- df2$day[j] 
    }
  }
}

自分で試したこと

merge関数なども試してみましたが、思い通りの処理にはなりませんでした。

0 likes

3Answer

検証してみました
df1 77000レコード
df2 1500レコード
で動かしました。

最初のコードでは約20秒
後のコードでは2秒程で処理完了していました。

私のコードでは5分半もかかっていましたので、驚異的な改善となりました。

感謝でいっぱいです。ありがとうございました。

1Like

下記のような方法はいかがでしょうか。
R言語はほとんど知らないので、もっと良いやり方があるかも知れません。

IDに不在や重複がない場合

code
df1 <- data.frame(
  ID = c(0,1,2,3,4,5,6,7,8,9),
  day = c('a','b','c','d','e','f','g','h','i','j')
)
df2 <- data.frame(
  ID = c(9,8,7,6,5,4,3,2,1,0),
  day = c('A','B','C','D','E','F','G','H','I','J')
)

for (i in 1:nrow(df1)) {
    df1$day[i] <- df2$day[df2$ID == df1$ID[i]] # IDが一致する行のdayを得る
}
df1
result
   ID day
1   0   J
2   1   I
3   2   H
4   3   G
5   4   F
6   5   E
7   6   D
8   7   C
9   8   B
10  9   A

IDに不在や重複がある場合

code
df1 <- data.frame(
  ID = c(0,1,2,3,4,5,6,7,8,9),
  day = c('a','b','c','d','e','f','g','h','i','j')
)
df2 <- data.frame(
  ID = c(9,8,7,6,5,4,3,2,1,9), # 重複や不在が存在すると仮定したデータ例
  day = c('A','B','C','D','E','F','G','H','I','J')
)

for (i in 1:nrow(df1)) {
    day <- df2$day[df2$ID == df1$ID[i]] # IDが一致する行のdayを得る
    len <- length(day) # 不在なら0、重複があれば>1
    if (len > 0) {
        df1$day[i] <- day[len] # 重複がある場合は後の行が優先、最初の行を優先するならlenを1にする
    }
}
result
   ID day
1   0   a
2   1   I
3   2   H
4   3   G
5   4   F
6   5   E
7   6   D
8   7   C
9   8   B
10  9   J
0Like

Comments

  1. @miya-t

    Questioner

    早速の返信ありがとうございます。

    コード実行してみました。かなり早いです。体感的には数十倍速いと思います。
    このようなコートが、素早く書けるように精進したいと思います。

IDに不在や重複がないことが前提ですが、下記のようにも書けるようです。

code
df1 <- data.frame(
  ID = c(0,1,2,3,4,5,6,7,8,9),
  day = c('a','b','c','d','e','f','g','h','i','j')
)
df2 <- data.frame(
  ID = c(9,8,7,6,5,4,3,2,1,0),
  day = c('A','B','C','D','E','F','G','H','I','J')
)

df1$day <- sapply(1:nrow(df1), function(i){df2$day[df2$ID == df1$ID[i]]})
df1
result
   ID day
1   0   J
2   1   I
3   2   H
4   3   G
5   4   F
6   5   E
7   6   D
8   7   C
9   8   B
10  9   A

追記

不在や重複がある場合は、こうなります。

code
df1 <- data.frame(
  ID = c(0,1,2,3,4,5,6,7,8,9),
  day = c('a','b','c','d','e','f','g','h','i','j')
)
df2 <- data.frame(
  ID = c(9,8,7,6,5,4,3,2,1,9),
  day = c('A','B','C','D','E','F','G','H','I','J')
)

df1$day <- sapply(1:nrow(df1), function(i){
    day <- df2$day[df2$ID == df1$ID[i]]
    len <- length(day)
    if ( len > 0 ) day[len] else df1$day[i]
})
df1
result
   ID day
1   0   a
2   1   I
3   2   H
4   3   G
5   4   F
6   5   E
7   6   D
8   7   C
9   8   B
10  9   J
0Like

Comments

  1. @miya-t

    Questioner

    ありがとうございます。
    重複は無いのですが、不在はあります。forが無いのでこれができたら最速だったかもしれませんね。
    勉強になります
  2. 不在と重複に対応したコードを追記しました。

    `sapply`は、内部的にループを作り出しているようなものですので、速さについては検証が必要だと思われます。

Your answer might help someone💌