J'essaie de comprendre comment rechercher une valeur en utilisant plusieurs colonnes. Je n'arrive tout simplement pas à le faire fonctionner correctement. Voici un exemple:
g1 g2 value 1 a 1 100 2 b 2 200 3 c 3 NA 4 c 4 300
J'ai donc essayé de faire:
df1$value <- df2[match(df1$g1, df2$g.1) & match(df1$g2, df2$g.2),]$val
Mais cela ne fonctionne pas pour la dernière valeur et je devine cela ne fonctionne que pour les 2 premiers juste par erreur. J'aimerais que df1 ressemble à:
df1 <- data.frame(g1 = c("a", "b", "c", "c"), g2 = c(1, 2, 3, 4))
df2 <- data.frame(g.1 = c("a", "b", "c"), g.2 = c(1, 2, 4), val = c(100, 200, 300))
3 Réponses :
Essayez une jointure gauche en utilisant merge:
transform(df1, val = df2$val[match(paste(g1, g2), paste(df2$g.1, df2$g.2))])
library(sqldf)
sqldf("select df1.*, df2.val
from df1 left join df2 on g1 = [g.1] and g2 = [g.2]")
library(dplyr)
df1 %>% left_join(df2, by = c(g1 = "g.1", g2 = "g.2"))
giving:
g1 g2 val 1 a 1 100 2 b 2 200 3 c 3 NA 4 c 4 300
Voici quelques alternatives:
merge(df1, df2, by = 1:2, all.x = TRUE)
a mis à jour la question pour montrer que les colonnes du groupe sont différentes. Je suppose donc que je devrais utiliser "par" avec fusion.
Une jointure serait meilleure et avec data.table , elle devient plus efficace car nous mettons à jour ma référence
p1 <- do.call(paste, df1) p2 <- do.call(paste, df2[1:2]) i1 <- match(p1, p2, nomatch = 0) i2 <- match(p2, p1, nomatch = 0) df1$value[i2] <- df2$val[i1] df1 # g1 g2 value #1 a 1 100 #2 b 2 200 #3 c 3 NA #4 c 4 300
Avec match , une approche serait de coller les colonnes d'intérêt ensemble, puis de créer un seul index pour changer les valeurs
library(data.table) setDT(df1)[df2, value := val, on = .(g1 = g.1, g2 = g.2)] df1 # g1 g2 value #1: a 1 100 #2: b 2 200 #3: c 3 NA #4: c 4 300
J'ai compris ce que je fais de mal en me basant sur @G. Réponse de Grothendieck. Tout ce que j'avais à faire était:
df1$value <- df2[match(paste0(df1$g1,df1$g2), paste0(df2$g.1,df2$g.2)),]$val
Faites simplement une jointure
setDT (df1) [df2, value: = val, on =. (G1, g2)]De plus,
matchrenvoie un index numérique, donc le&ne fonctionnera pas comme vous le souhaitezsetDT fait-il partie de la base R? (essayant de rester dans les packages de base R si possible mais intéressé par d'autres packages également)
C'est la syntaxe data.table, mais si vous voulez la base R, alors
mergeest mieuxLes changements de noms de colonnes peuvent être reflétés avec
setDT (df1) [df2, value: = val, on =. (G1 = g.1, g2 = g.2)]@akrun, n'hésitez pas à ajouter cela comme réponse