Scal ramki danych przy dopasowywaniu A, B i * najbliższej * C?
Mam dwie ramki danych:
set.seed(1)
df <- cbind(expand.grid(x=1:3, y=1:5), time=round(runif(15)*30))
to.merge <- data.frame(x=c(2, 2, 2, 3, 2),
y=c(1, 1, 1, 5, 4),
time=c(17, 12, 11.6, 22.5, 2),
val=letters[1:5],
stringsAsFactors=F)
Chcę się połączyćto.merge
wdf
(zall.x=T
) takie, że:
df$x == to.merge$x
Idf$y == to.merge$y
Iabs(df$time - to.merge$time) <= 1
; w przypadku wielokrotnościto.merge
które spełniają, wybieramy ten, który minimalizuje te odległości.Jak mogę to zrobić?
Więc moim pożądanym rezultatem jest (to jest po prostudf
z odpowiednimvalue
kolumnato.merge
dodane dla pasujących wierszy):
x y time val
1 1 1 8 NA
2 2 1 11 c
3 3 1 17 NA
4 1 2 27 NA
5 2 2 6 NA
6 3 2 27 NA
7 1 3 28 NA
8 2 3 20 NA
9 3 3 19 NA
10 1 4 2 NA
11 2 4 6 NA
12 3 4 5 NA
13 1 5 21 NA
14 2 5 12 NA
15 3 5 23 d
gdzieto.merge
było:
x y time val
1 2 1 17.0 a
2 2 1 12.0 b
3 2 1 11.6 c
4 3 5 22.5 d
5 2 4 2.0 e
Uwaga - (2, 1, 17, a) nie pasuje dodf
ponieważtime
17 było więcej niż 1 oddf$time
11 dla (X, Y) = (2, 1).
Ponadto były dwa rzędyto.merge
to spełniało warunek dopasowania dodf
wiersz (2, 1, 11), ale wiersz „c” został wybrany zamiast wiersza „b”, ponieważ jesttime
był najbliższy 11.
Wreszcie mogą być wierszeto.merge
które nie pasują do niczegodf
.
Jednym ze sposobów działania jest pętla for-loop, ale moje dane zajmują zbyt dużo czasu (df
ma ~ 12k rzędów ito.merge
ma ~ 250 tys. wierszy)
df$value <- NA
for (i in 1:nrow(df)) {
row <- df[i, ]
idx <- which(row$x == to.merge$x &
row$y == to.merge$y &
abs(row$time - to.merge$time) <= 1)
if (length(idx)) {
j <- idx[which.min(row$time - to.merge$time[idx])]
df$val[i] <- to.merge$val[j]
}
}
Czuję, że mogę jakoś połączyć się, jak:
to.merge$closest_time_in_df <- sapply(to.merge$time,
function (tm) {
dts <- abs(tm - df$time)
# difference must be at most 1
if (min(dts) <= 1) {
df$time[which.min(dts)]
} else {
NA
}
})
merge(df, to.merge,
by.x=c('x', 'y', 'time'),
by.y=c('x', 'y', 'closest_time_in_df'),
all.x=T)
Ale to nie łączy(2, 1, 11)
wiersz, ponieważto.merge$closest_time_in_df
dla(2, 1, 11.5, c)
wynosi 12, ale czas 12 calidf
odpowiada (x, y) = (2, 5) nie (2, 1) stąd połączenie nie powiedzie się.