2017-07-11 1 views
1

J'ai deux dfComment joindre des dataframes conditionnellement sur des paires de colonnes?

d1 <- data_frame(name=c('Mike','Carl','Joe', 'Mike'), 
      id=c(1,2,NA,1), 
      id2=c('a',NA,'c','a'), 
      dateT=as.Date('2017-05-01','2017-05-01','2017-05-01','2016-05-01')) 


    # A tibble: 4 x 4 
    name id id2  dateT 
    <chr> <dbl> <chr>  <date> 
1 Mike  1  a 2017-05-01 
2 Carl  2 <NA> 2017-05-01 
3 Joe NA  c 2017-05-01 
4 Mike  1  a 2016-05-01 

d2 <- data_frame(value=c(T, T, F, T,F), 
       id=c(1,2,3,1,4), 
       id2=c('a','b','c','a','d'), 
       dateT=as.Date('2017-05-01','2017-05-01','2017-05-01', '2016-05-01','2016-05-01')) 
# A tibble: 5 x 4 
    value id id2  dateT 
    <lgl> <dbl> <chr>  <date> 
1 TRUE  1  a 2017-05-01 
2 TRUE  2  b 2017-05-01 
3 FALSE  3  c 2017-05-01 
4 TRUE  1  a 2016-05-01 
5 FALSE  4  d 2016-05-01 

Et je suis en train de rejoindre d2 avec d1 base paires dateT et idoudate et id2 dépend sur lequel est disponible. Finalement, je voudrais avoir tous les enregistrements de d2 (qu'ils soient ou non assortis), et joint toutes les colonnes de d1 qui ont une correspondance sur d2.

Ce que j'ai à ce jour est

d2 %>% 
    inner_join(d1, by=c('id'='id', 'dateT'='dateT')) 



# A tibble: 5 x 6 
    value id id2.x  dateT name id2.y 
    <lgl> <dbl> <chr>  <date> <chr> <chr> 
1 TRUE  1  a 2017-05-01 Mike  a 
2 TRUE  2  b 2017-05-01 Carl <NA> 
3 FALSE  3  c 2017-05-01 <NA> <NA> 
4 TRUE  1  a 2016-05-01 Mike  a 
5 FALSE  4  d 2016-05-01 <NA> <NA> 

Il y a deux questions:

  1. je préférerais joindre que name de d1, puisque dans mon cas id2.y est toujours va être un sous-ensemble id2.x (Je veux garder seulement id2.x car il sera toujours le plus complet). Je sais que je peux laisser tomber les colonnes plus tard, mais je me demandais si dplyr avait une fonctionnalité qui ne garderait que les colonnes de la première image en présence de noms de colonne dupliqués

  2. Je ne sais pas comment regarder conditionnellement id2 quand is.na(id)==T

La sortie attendue ressemblerait à ceci:

# A tibble: 5 x 6 
    value id id2  dateT name 
    <lgl> <dbl> <chr>  <date> <chr> 
1 TRUE  1  a 2017-05-01 Mike 
2 TRUE  2  b 2017-05-01 Carl 
3 FALSE  3  c 2017-05-01 Joe 
4 TRUE  1  a 2016-05-01 Mike 
5 FALSE  4  d 2016-05-01 <NA> 
+0

Pouvez-vous s'il vous plaît publier votre sortie attendue? – Sotos

+0

@Sotos sortie ajoutée, désolé – Dambo

Répondre

1

Que pensez-vous de cela?

# first join by id, dropping id2 
join1 = select(d1, -id2) %>% 
    inner_join(d2, ., by=c("dateT", "id")) 
# now take what couldn't be joined with id, 
# drop id, join by id2, + left join to keep the remainder 
join2 = d2 %>% 
    anti_join(d1, by=c("dateT", "id")) %>% 
    left_join(select(d1, -id), by=c("dateT", "id2")) 

bind_rows(join1, join2) 

# A tibble: 5 x 5 
    value id id2  dateT name 
    <lgl> <dbl> <chr>  <date> <chr> 
1 TRUE  1  a 2017-05-01 Mike 
2 TRUE  2  b 2017-05-01 Carl 
3 TRUE  1  a 2016-05-01 Mike 
4 FALSE  4  d 2016-05-01 <NA> 
5 FALSE  3  c 2017-05-01 Joe 

Notez que ce code tente d'utiliser id2 chaque fois id rejoindre échoue, non seulement quand id est NA. Franchement, mon approche nécessite trois jointures, donc sur un énorme jeu de données, il peut être plus rapide de recoder la variable id - mais c'est difficile à faire sans savoir ce que cela signifie dans vos données.

1

Essayez:

library(dplyr) 

d1 <- data_frame(name=c('Mike','Carl','Joe', 'Mike'), 
       id=c(1,2,NA,1), 
       id2=c('a',NA,'c','a'), 
       dateT=as.Date(c('2017-05-01','2017-05-01','2017-05-01','2016-05-01'))) 
# add combine-"c" !! 

d2 <- data_frame(value=c(T, T, F, T,F), 
       id=c(1,2,3,1,4), 
       id2=c('a','b','c','a','d'), 
       dateT=as.Date(c('2017-05-01','2017-05-01','2017-05-01', '2016-05-01','2016-05-01'))) 
# add combine-"c" !! 

left_join(d2, 
      d1 %>% 
      select(name, id, dateT) %>% 
      rename(name1=name), 
      by=c("id", "dateT")) %>% 
    left_join(d1 %>% 
       select(name, id2, dateT) %>% 
       rename(name2=name), 
      by=c("id2", "dateT")) %>% 
    transmute(value, id, id2, dateT, 
      name=ifelse(is.na(name1),name2,name1)) 
+0

Merci, la sortie semble bonne, mais je trouve difficile de généraliser votre approche pour les grands ensembles de données. Le problème est qu'il n'est pas vraiment conditionnel à la valeur de id/id2 – Dambo