web-dev-qa-db-fra.com

Fusionner des images de données inégales et remplacer les lignes manquantes par 0

J'ai deux data.frames, une avec seulement des caractères et l'autre avec des caractères et des valeurs.

df1 = data.frame(x=c('a', 'b', 'c', 'd', 'e'))
df2 = data.frame(x=c('a', 'b', 'c'),y = c(0,1,0))
merge(df1, df2)
  x y
1 a 0
2 b 1
3 c 0 

Je veux fusionner df1 et df2. Les caractères a, b et c ont bien fusionné et ont également 0, 1, 0 mais d et e n’ont rien. Je veux d et e aussi dans la table de fusion, avec la condition 0 0. Ainsi, pour chaque ligne manquante sur le fichier data.frame de df2, le 0 doit être placé dans la table df1, comme suit:

  x y
1 a 0
2 b 1
3 c 0
4 d 0
5 e 0
59
Lisann

Consultez la page d'aide pour la fusion. Le paramètre all vous permet de spécifier différents types de fusion. Ici, nous voulons définir all = TRUE. La fusion renverra NA pour les valeurs qui ne correspondent pas, que nous pouvons mettre à jour à 0 avec is.na():

zz <- merge(df1, df2, all = TRUE)
zz[is.na(zz)] <- 0

> zz
  x y
1 a 0
2 b 1
3 c 0
4 d 0
5 e 0

Mis à jour plusieurs années plus tard pour répondre à la question suivante

Vous devez identifier les noms de variable dans la deuxième table de données sur laquelle vous ne fusionnez pas - J'utilise setdiff() pour cela. Découvrez les éléments suivants:

df1 = data.frame(x=c('a', 'b', 'c', 'd', 'e', NA))
df2 = data.frame(x=c('a', 'b', 'c'),y1 = c(0,1,0), y2 = c(0,1,0))

#merge as before
df3 <- merge(df1, df2, all = TRUE)
#columns in df2 not in df1
unique_df2_names <- setdiff(names(df2), names(df1))
df3[unique_df2_names][is.na(df3[, unique_df2_names])] <- 0 

Créé le 2019-01-03 par le paquetage reprex (v0.2.1)

89
Chase

Ou, comme alternative au code de @ Chase, être un fan récent de plyr ayant une expérience dans les bases de données:

require(plyr)
zz<-join(df1, df2, type="left")
zz[is.na(zz)] <- 0
7
Nick Sabbe

Une autre alternative avec data.table.

EXEMPLE DE DONNÉES

dt1 <- data.table(df1)
dt2 <- data.table(df2)
setkey(dt1,x)
setkey(dt2,x)

CODE

dt2[dt1,list(y=ifelse(is.na(y),0,y))]
3
Wojciech Sobala

J'ai utilisé la réponse donnée par Chase (réponse du 11 mai à 14h21), mais j'ai ajouté un peu de code pour appliquer cette solution à mon problème particulier.

J'avais une trame de taux (utilisateur, téléchargement) et une trame de totaux (utilisateur, téléchargement) à fusionner par utilisateur, et je voulais inclure tous les taux, même s'il n'y avait pas de total correspondant. Cependant, il ne peut y avoir aucun total manquant, auquel cas la sélection des lignes pour le remplacement de NA par zéro échouerait.

La première ligne de code fait la fusion. Les deux lignes suivantes modifient les noms de colonne dans le cadre fusionné. L'instruction if remplace NA par zéro, mais uniquement s'il existe des lignes avec NA.

# merge rates and totals, replacing absent totals by zero
graphdata <- merge(rates, totals, by=c("user"),all.x=T)
colnames(graphdata)[colnames(graphdata)=="download.x"] = "download.rate"
colnames(graphdata)[colnames(graphdata)=="download.y"] = "download.total"
if(any(is.na(graphdata$download.total))) {
    graphdata[is.na(graphdata$download.total),]$download.total <- 0
}
2
Ian E. Gorman

En supposant que df1 A toutes les valeurs de x d'intérêt, vous pouvez utiliser un dplyr::left_join() pour fusionner, puis un base::replace() ou tidyr::replace_na() pour remplacer le NAs en tant que 0 s:

library(tidyverse)

# dplyr only:
df_new <- 
  left_join(df1, df2, by = 'x') %>% 
  mutate(y = replace(y, is.na(y), 0))

# dplyr and tidyr:
df_new <- 
  left_join(df1, df2, by = 'x') %>% 
  mutate(y = replace_na(y, 0))

# In the sample data column `x` is a factor, which will give a warning with the join. This can be prevented by converting to a character before the join:
df_new <- 
  left_join(df1 %>% mutate(x = as.character(x)), 
            df2 %>% mutate(x = as.character(x)), 
            by = 'x') %>% 
    mutate(y = replace(y, is.na(y), 0))
1
sbha