Tengo este marco de datos:

df1<-data.frame(ID_NUMBER = c(7160015,22695229,22695230,7160016,7160017,22695198,7160018,22695199,7160019,22695200,7160020,22695232,7160030,22697153,22697158,7162962,22698039,22698041,7162964) 
, CalNumber = c(9662.37,9662.45,9663.41,9663.44,9665.97,9666.11,9667.04,9667.1,9667.87,9668.01,9668.74,9668.79,9868.2, 72719.75,72723.21,99774,99774.03,99776.11,99776.13)
,Inspection_Date = c('11/13/2009','10/8/2014','10/8/2014','11/13/2009','11/13/2009','10/8/2014','11/13/2009','10/8/2014','11/13/2009','10/8/2014','11/13/2009','10/8/2014','11/13/2009','10/8/2014','10/8/2014','11/13/2009','10/8/2014','10/8/2014','11/13/2009'))

Estoy tratando de hacer coincidir los registros del 08/10/2014 con los registros del 13/11/2009 en función de la proximidad más cercana a CalNumber (que es la diferencia absoluta que es <= 1). Los registros están ordenados por CalNumber. El récord más pequeño del 13/11/2009 podría ser el antes o después del récord del 10/08/2014. Una vez que un registro del 08/10/2014 se compara con el registro más cercano del 13/11/2009, ese registro del 13/11/2009 no se considera para más coincidencias.

Lo siento si es confuso. Ojalá esto lo explique mejor. Así es como se vería el conjunto de resultados final.

df1<-data.frame(ID_NUMBER = c(7160015,22695229,22695230,7160016,7160017,22695198,7160018,22695199,7160019,22695200,7160020,22695232,7160030,22697153,22697158,7162962,22698039,22698041,7162964) 
, CalNumber = c(9662.37,9662.45,9663.41,9663.44,9665.97,9666.11,9667.04,9667.1,9667.87,9668.01,9668.74,9668.79,9868.2, 72719.75,72723.21,99774,99774.03,99776.11,99776.13)
,Inspection_Date = c('11/13/2009','10/8/2014','10/8/2014','11/13/2009','11/13/2009','10/8/2014','11/13/2009','10/8/2014','11/13/2009','10/8/2014','11/13/2009','10/8/2014','11/13/2009','10/8/2014','10/8/2014','11/13/2009','10/8/2014','10/8/2014','11/13/2009')
,Diff = c(NA,0.08,0.03,NA,NA,0.14,NA,0.06,NA,0.14,NA,0.05,NA, NA,NA,NA,0.03,0.02,NA)
,MatchID = c(NA,7160015,7160016,NA,NA,7160017,NA,7160018,NA,7160019,NA,7160020,NA, NA,NA,NA,7162962,7162964,NA))

El conjunto de resultados final tiene 2 columnas adicionales. Diff (abs (CalNumber) <= 1), que es la diferencia de abs del registro más cercano basado en CalNumber. MatchID, que es el ID_Number correspondiente que era el registro más cercano. Si el 10/08/2014 no tiene una coincidencia <= 1, entonces se deja en blanco. Todas las columnas MatchID del 13/11/2009 están en blanco. El MatchID solo se completa para los registros del 08/10/2014 con coincidencias más cercanas del 13/11/2009.

Gracias de antemano!!

r
1
yanci 16 oct. 2018 a las 17:52

2 respuestas

La mejor respuesta

Soy relativamente nuevo en data.table, así que tengan paciencia conmigo:

library(data.table)

dt1 <- data.table(df1)
dt2 <- copy(dt1)

setnames(dt2, c("ID_NUMBER", "CalNumber", "Inspection_Date"), c("ID_NUMBER2", "CalNumber2", "Inspection_Date2"))

dt2[dt1,
    .(ID_NUMBER,
      CalNumber,
      Inspection_Date,
      Diff = abs(CalNumber - CalNumber2),
      MatchID = ID_NUMBER2),
    on = .(Inspection_Date2 > Inspection_Date),
    allow.cartesian = TRUE
    ][,
      .SD[which.min(ifelse(is.na(Diff), Inf, Diff))],
      by = .(ID_NUMBER, CalNumber, Inspection_Date)
      ][,
        .(ID_NUMBER,
          CalNumber,
          Inspection_Date,
          Diff = ifelse(Diff > 1, NA, Diff),
          MatchID = ifelse(Diff > 1, NA, MatchID))
        ]

    ID_NUMBER CalNumber Inspection_Date Diff MatchID
 1:   7160015   9662.37      11/13/2009   NA      NA
 2:  22695229   9662.45       10/8/2014 0.08 7160015
 3:  22695230   9663.41       10/8/2014 0.03 7160016
 4:   7160016   9663.44      11/13/2009   NA      NA
 5:   7160017   9665.97      11/13/2009   NA      NA
 6:  22695198   9666.11       10/8/2014 0.14 7160017
 7:   7160018   9667.04      11/13/2009   NA      NA
 8:  22695199   9667.10       10/8/2014 0.06 7160018
 9:   7160019   9667.87      11/13/2009   NA      NA
10:  22695200   9668.01       10/8/2014 0.14 7160019
11:   7160020   9668.74      11/13/2009   NA      NA
12:  22695232   9668.79       10/8/2014 0.05 7160020
13:   7160030   9868.20      11/13/2009   NA      NA
14:  22697153  72719.75       10/8/2014   NA      NA
15:  22697158  72723.21       10/8/2014   NA      NA
16:   7162962  99774.00      11/13/2009   NA      NA
17:  22698039  99774.03       10/8/2014 0.03 7162962
18:  22698041  99776.11       10/8/2014 0.02 7162964
19:   7162964  99776.13      11/13/2009   NA      NA

La copia de dt1 se debió a que tuve problemas para hacer referencia a columnas durante la autounión. También sospecho que algunas de las operaciones se pueden consolidar, por lo que la entrada de otros usuarios es muy bienvenida.

Lógica:

  • El primer conjunto de corchetes realiza uniones de desigualdad a la izquierda de dt1 con dt2, calcula la variable Diff. La sintaxis de combinación izquierda de data.table es un poco extraña, pero lo que está haciendo es tomar todas las filas de dt2 que coinciden con lo especificado en el argumento on

  • El segundo conjunto de corchetes obtiene los registros que coinciden con un valor mínimo dentro de un grupo. Aquí el valor es una variable Diff ligeramente alterada (consulte esta publicación que usé para obtener ayuda)

  • Los terceros corchetes asignan NA a Diff y MatchID valores donde el mínimo Diff estaba por encima de 1

2
zack 16 oct. 2018 a las 17:59

Gracias a la respuesta de @ zack, creo que ahora entiendo lo que está haciendo el OP. Para encontrar la coincidencia más cercana, normalmente se puede utilizar una combinación continua:

setDT(df1)
df1[Inspection_Date == "10/8/2014", c("md", "mid") := 
  df1[Inspection_Date == "11/13/2009"][.SD, on=.(CalNumber), roll="nearest", 
    .(abs(x.CalNumber - i.CalNumber), x.ID_NUMBER)
  ]
]

# oh, and then wipe it out if diff > 1
df1[md > 1, c("md", "mid") := NA]


    ID_NUMBER CalNumber Inspection_Date Diff MatchID   md     mid
 1:   7160015   9662.37      11/13/2009   NA      NA   NA      NA
 2:  22695229   9662.45       10/8/2014 0.08 7160015 0.08 7160015
 3:  22695230   9663.41       10/8/2014 0.03 7160016 0.03 7160016
 4:   7160016   9663.44      11/13/2009   NA      NA   NA      NA
 5:   7160017   9665.97      11/13/2009   NA      NA   NA      NA
 6:  22695198   9666.11       10/8/2014 0.14 7160017 0.14 7160017
 7:   7160018   9667.04      11/13/2009   NA      NA   NA      NA
 8:  22695199   9667.10       10/8/2014 0.06 7160018 0.06 7160018
 9:   7160019   9667.87      11/13/2009   NA      NA   NA      NA
10:  22695200   9668.01       10/8/2014 0.14 7160019 0.14 7160019
11:   7160020   9668.74      11/13/2009   NA      NA   NA      NA
12:  22695232   9668.79       10/8/2014 0.05 7160020 0.05 7160020
13:   7160030   9868.20      11/13/2009   NA      NA   NA      NA
14:  22697153  72719.75       10/8/2014   NA      NA   NA      NA
15:  22697158  72723.21       10/8/2014   NA      NA   NA      NA
16:   7162962  99774.00      11/13/2009   NA      NA   NA      NA
17:  22698039  99774.03       10/8/2014 0.03 7162962 0.03 7162962
18:  22698041  99776.11       10/8/2014 0.02 7162964 0.02 7162964
19:   7162964  99776.13      11/13/2009   NA      NA   NA      NA

Estoy codificando fechas específicas basadas en OP's ...

Estoy tratando de hacer coincidir los registros del 08/10/2014 con los registros del 13/11/2009 en función de la proximidad más cercana a CalNumber (que es la diferencia absoluta que es <= 1).

... mientras que la respuesta de Zack compara fechas de manera más general. (Tenga en cuenta que debe usar un formato de fecha adecuado para esto, por ejemplo, df1[, Inspection_Date := as.IDate(Inspection_Date, "%m/%d/%Y")])


Cómo funciona

La parte clave es una combinación x[i, on=, roll=, j] del subconjunto de 2009 x = df1[Inspection_Date == "11/13/2009"] y el subconjunto de 2014 i = .SD = df1[Inspection_Date == "10/8/2014"] según las condiciones en on= y roll=.

Dentro de j de x[i, on=, roll=, j], los prefijos x.* y i.* se pueden usar para eliminar la ambigüedad de los nombres de columnas comunes.

2
Frank 16 oct. 2018 a las 18:30