Supongamos que tengo dos marcos de datos como el siguiente:

df1 <- data.frame(
    X = c(1,2,2),
    Y = c("a","b","c"),
    Z = c(10,20,30)
)

df2 <- data.frame(
  X = c(1,2,2,4),
  Y = c(NA,"b","c","d"),
  W = c(-1,-2,-3,-4)
)

Me gustaría dejar unir df1 en df2 usando X e Y. Pero para la primera observación solo usaría X. Al final me gustaría obtener:

df3 <- data.frame(
  X = c(1,2,2,4),
  Y = c(NA,"b","c","d"),
  W = c(-1,-2,-3,-4),
  Z = c(10,20,30,NA)
)

No se pudo hacerlo usando left_join o full_join.

0
Gabriel Jardanovski 26 jun. 2020 a las 01:17

2 respuestas

No es el más elegante, pero no sé cómo hacer (bueno) uniones condicionales:

full_join(df2, df1, by = c("X", "Y")) %>%
  filter(!is.na(W)) %>%
  group_by(grp = is.na(Y)) %>%
  do({
    dat <- .
    if (is.na(dat$Y[1])) {
      left_join(dat, select(df1, -Y), by = "X") %>%
        mutate(Z = coalesce(Z.x, Z.y)) %>%
        select(-starts_with("Z."))
    } else dat
  }) %>%
  ungroup() %>%
  select(-grp) %>%
  arrange(X, Y)
# # A tibble: 4 x 4
#       X Y         W     Z
#   <dbl> <chr> <dbl> <dbl>
# 1     1 <NA>     -1    10
# 2     2 b        -2    20
# 3     2 c        -3    30
# 4     4 d        -4    NA
0
r2evans 25 jun. 2020 a las 22:34

Puedes hacer esto en dos pasos. Primero, unir a la izquierda df2 en df1 usando X e Y. Segundo, reemplazar cualquier valor faltante en Z con el valor correspondiente en df1 basado solo en X. Pero esto solo funcionará si no hay duplicados en X.

df4 <- merge(df2, df1, all.x=TRUE); df4
#  X    Y  W  Z
#1 1 <NA> -1 NA # <-- this guy could not match, since Y was NA
#2 2    b -2 20
#3 2    c -3 30
#4 4    d -4 NA

ind <- df4$X[is.na(df4$Z)] # returns the indices 1 4
df4$Z[ind] <- df1$Z[ind]
df4
#  X    Y  W  Z
#1 1 <NA> -1 10
#2 2    b -2 20
#3 2    c -3 30
#4 4    d -4 NA

Si df2 $ Y contiene NA para cualquier X que esté duplicada, entonces la solución es indeterminada.

0
Edward 26 jun. 2020 a las 00:51