¿Combinar marcos de datos en A, B y * más cercanos * C?
Tengo dos marcos de datos así:
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)
Quiero fusionarto.merge
dentrodf
(conall.x=T
) tal que:
df$x == to.merge$x
Ydf$y == to.merge$y
Yabs(df$time - to.merge$time) <= 1
; en el caso de multiplesto.merge
que satisfacen, escogemos la que minimice estas distancias.¿Cómo puedo hacer esto?
Así que mi resultado deseado es (esto es solodf
con el correspondientevalue
columna deto.merge
añadido para las filas coincidentes):
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
dóndeto.merge
estaba:
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
Nota: (2, 1, 17, a) no coincidió condf
porque eltime
17 estaba a más de 1 de distancia.df$time
11 para (X, Y) = (2, 1).
Además, había dos filas ento.merge
que cumplía la condición de emparejar adf
's (2, 1, 11) fila, pero la fila' c 'fue elegida en lugar de la fila' b 'porque estime
Fue el más cercano al 11.
Finalmente, puede haber filas ento.merge
que no coinciden con nada endf
.
Una forma que funciona es un bucle for, pero toma demasiado tiempo para mis datos (df
tiene ~ 12k filas yto.merge
tiene ~ 250k filas)
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]
}
}
Siento que de alguna manera puedo hacer una fusión, como:
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)
Pero esto no fusiona el(2, 1, 11)
fila porqueto.merge$closest_time_in_df
para(2, 1, 11.5, c)
es 12, pero un tiempo de 12 endf
corresponde a (x, y) = (2, 5) no (2, 1) por lo tanto, la combinación falla.