¿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.

Respuestas a la pregunta(3)

Su respuesta a la pregunta