この質問にはすでに答えがあります:
R での複雑な非等価マージ
(答えは3つ)
3 年前
に閉店しました。
R でネストされた for ループを作成しましたが、ループの実行に時間がかかりすぎます。 2 つの大きなデータセットがあります。 dfA のすべての行と dfB のすべての行について、ループは dfA の日付が dfB の日付間隔内にあるかどうかを確認する必要があります。これならが true の場合、2 つのデータセットはその行の特定の列でマージされます。ループがまだ実行されているため、私が書いたコードがエラーなしで動作するかどうかはわかりません。
何か洞察があれば幸いです。
dfA:
Common a Date
1 20141331123 1 2005-01-01
2 20141331123 2 2005-01-02
3 20141331123 3 2005-01-03
4 20141331123 4 2005-01-04
5 20141331123 5 2005-01-05
6 20141331123 6 2005-01-06
dfB:
cDate bDate common
1 2005-01-01 2005-06-13 20141331123
dfB$Interval <- interval(ymd(dfB$cDate), ymd(dfB$bDate))
library(lubridate)
for (i in 1:nrow(dfA)) {
for (i in 1:nrow(dfB)) {
if (dfA$Date[i] %within% dfB$Interval[i] == TRUE) {
merged <- merge(dfA, dfB, by.x = c("common"), by.y = c("Common"))
}
}
return(merged)
}
(1) コードはすべての結果を破棄しています。マージしたい場合は、その戻り値をどこかにキャプチャする必要があります。それがなければ、何の成果も示さないまま、すべての仕事をこなしていることになります。 (2) 範囲ベースの結合操作を検討している場合は、非等価結合を実行することを強くお勧めします。ループを試みるのをやめてください。 data.table と SQL はこれをネイティブに実行します (残念ながら、base-R と dplyr は実行しません)。
– r2evans
2020 年 9 月 4 日 20:54
...では、apply() はここでどこに登場するのでしょうか?
– r2evans
2020 年 9 月 4 日 20:55
dput を使用して、小さく代表的なサンプル データを提供していただければ非常に役立ちます。つまり、それぞれから少数の行があり、一部の行はマージされ、一部の行はマージされません。
– r2evans
2020 年 9 月 4 日 20:58
データを追加しました。 dfA の日付が dfB の日付間隔内にあるかどうかを確認したいため、lubridate を使用しました。 apply() が for ループを置き換えるのに役立つのではないかと思いました。私の理解は間違っている可能性があります。私はまだリーですR の使用方法について説明します。
– user12310746
2020 年 9 月 4 日 21:08
------------------------
非等価結合は、SQL と R 内の data.table でネイティブにサポートされています。基本 R 関数も Tidyverse 関数もローカルではサポートしていません [1]。
library(data.table)
setDT(dfA)
setDT(dfB)
dfB[dfA, on = .(common == Common, cDate <= Date, bDate >= Date)]
# cDate bDate common a
# 1: 2005-01-01 2005-01-01 20141331123 1
# 2: 2005-01-02 2005-01-02 20141331123 2
# 3: 2005-01-03 2005-01-03 20141331123 3
# 4: 2005-01-04 2005-01-04 20141331123 4
# 5: 2005-01-05 2005-01-05 20141331123 5
# 6: 2005-01-06 2005-01-06 20141331123 6
サンプル データは、すべてが 1 つの間隔に収まるという点で少し面白くありませんが、おそらくこれは、より多様なデータで機能するでしょう。
[1]: SQL がサポートしているため、dbplyr では sql_on を使用してサポートされています。
データ:
dfA <- structure(list(Common = c("20141331123", "20141331123", "20141331123", "20141331123", "20141331123", "20141331123"), a = 1:6, Date = structure(c(12784, 12785, 12786, 12787, 12788, 12789), class = "Date")), row.names = c(NA, -6L), class = "data.frame")
dfB <- structure(list(cDate = structure(12784, class = "Date"), bDate = structure(12947, class = "Date"), common = "20141331123"), row.names = c(NA, -1L), class = "data.frame")
4
ありがとうございます。これは便利で非常に高速です。データは正しくマージされましたが、dfA の日付列も含めながらこのマージを行う方法はありますか?
– user12310746
2020 年 9 月 9 日 1:28
現時点では、Date 列の複製を作成して、最終的なデータテーブルに含めるようにしました。
– user12310746
2020 年 9 月 9 日 1:35
1
はい、非等価マージでは 3 つのフィールドのうち 1 つが失われる傾向があります (これは私も同じ不満です)。私もフィールドをコピーすることで対処しています。
– r2evans
2020 年 9 月 9 日 1:49
わかりました、わかりました。このマージの速さには本当に驚かされます。
– user12310746
2020 年 9 月 9 日 1:52
------------------------
データ サイズが許せば、単純なマージとサブセットを検討してください。
final_df <- subset(merge(dfA, dfB, by.x="Common", by.y="common"),
Date >= cDate & Date <= bDate)
final_df
# Common a Date cDate bDate
# 1 20141331123 1 2005-01-01 2005-01-01 2005-06-13
# 2 20141331123 2 2005-01-02 2005-01-01 2005-06-13
# 3 20141331123 3 2005-01-03 2005-01-01 2005-06-13
# 4 20141331123 4 2005-01-04 2005-01-01 2005-06-13
# 5 20141331123 5 2005-01-05 2005-01-01 2005-06-13
# 6 20141331123 6 2005-01-06 2005-01-01 2005-06-13
オンライン デモ
2
1
これは、ほぼデカルト展開 (コモンごと) から始まりますね?
– r2evans
2020 年 9 月 4 日 21:28
1
サンプルが示唆しているように、共通の値が両方のデータセットですべて同じであれば、はい。データ サイズが許せば、このソリューションは機能すると判断します。
– パフェ
2020 年 9 月 4 日 21:30