2010-07-06 5 views
14

J'essaie de comprendre comment utiliser merge() de mettre à jour une base de données.comment utiliser la fusion() pour mettre à jour une table en R

Voici un exemple. Prenons par exemple la trame de données foo

foo <- data.frame(index=c('a', 'b', 'c', 'd'), value=c(100, 101, NA, NA)) 

qui a les valeurs suivantes

index value 
1  a 100 
2  b 101 
3  c NA 
4  d NA 

Et la trame de données bar

bar <- data.frame(index=c('c', 'd'), value=c(200, 201)) 

qui a les valeurs suivantes:

index value 
1  c 200 
2  d 201 

Quand je lance la fonction merge() suivante pour mettre à jour les valeurs de c et d

merge(foo, bar, by='index', all=T) 

Il en résulte cette sortie:

index value.x value.y 
1  a  100  NA 
2  b  101  NA 
3  c  NA  200 
4  d  NA  201 

Je voudrais la sortie de merge() pour éviter la création de , dans cet exemple spécifique, de value.x et value.y, mais seulement conserver la colonne d'origine de value Y at-il un moyen simple de le faire?

+0

Ce que le résultat devrait être en cas de non nulls? –

+1

Avez-vous déjà reçu une réponse à cette question? Je suis à la recherche d'une solution pour ce même problème. – Gandalf

+0

Je me demande aussi pourquoi la fusion n'a pas, disons un paramètre 'overwrite = TRUE' qui entrerait quand' by' est fourni. Il est incessant de supprimer les colonnes manuellement chaque fois que vous voulez ré-exécuter une fusion. – Valentas

Répondre

7

N'a pas merge() BIND colonnes ensemble? Est-ce que replace() fonctionne?

foo$value <- replace(foo$value, foo$index %in% bar$index, bar$value) 

ou match() si l'ordre importe

foo$value[match(bar$index, foo$index)] <- bar$value 
+1

Un problème avec l'utilisation de 'replace()' est que si la commande dans 'bar' n'est pas la même que dans' foo', cela ne fonctionnera pas correctement. Par exemple, si vous essayez d'exécuter l'exemple ci-dessus après 'bar <-bar [c (2,1),]', le résultat final n'est pas correct. – andrewj

+0

vous avez raison à propos de match()? édité ci-dessus – apeescape

+0

Oui, 'match()' fonctionne pour mon exemple. En réalité, il s'avère que mon cas d'utilisation réel est plus compliqué, où je voudrais faire correspondre plusieurs colonnes et pas seulement un simple vecteur. Je ne pense pas que 'match()' fonctionne quand vous voulez faire correspondre plusieurs colonnes d'une base de données. – andrewj

0

merge() se fond que dans de nouvelles données. Par exemple, si vous possédez un ensemble de données de revenu moyen pour quelques villes et un ensemble de données distinct des populations de ces villes, vous utiliserez merge() pour fusionner un ensemble de données dans l'autre.

Comme apeescape dit, replace() est probablement ce que vous voulez.

2

Je voudrais également présenter une solution SQL à l'aide sqldf bibliothèque et la base de données SQLite-R intégré. J'aime la simplicité, l'exactitude et la puissance de sql.
exactitude: depuis que je peux définir exactement quel objet = lignes que je veux changer sans tenir compte de l'ordre d'un data.frame (foo.id = bar.id).
Puissance: dans WHERE après SET et WHERE (troisième rangée) je peux définir toutes les conditions que je veux envisager de mettre à jour.
Simplicité: la syntaxe est plus lisible que l'utilisation d'index dans les vecteurs, les matrices ou les données.

library(sqldf) 

# I changed index to id since index does not work. 
# Obviously index is a key word in sqlite. 

(foo <- data.frame(id=c('a', 'b', 'c', 'd'), value=c(100, 101, NA, NA))) 
(bar <- data.frame(id=c('c', 'd'), value=c(200, 201))) 

sqldf(c(paste("UPDATE foo" 
      ," SET value = (SELECT bar.value FROM bar WHERE foo.id = bar.id)" 
      ," WHERE value IS NULL" 
      ) 
     , " SELECT * FROM main.foo" 
    ) 
) 

Ce qui donne

id value 
1 a 100 
2 b 101 
3 c 200 
4 d 201 

questions similaires:
r equivalent of sql update?
R sqlite: update with two tables

+2

L'instruction SQL peut s'exécuter sur plusieurs lignes, donc 'paste' n'est pas nécessaire. –

+0

@Grothendieck Merci pour cette info. – giordano

0

Une autre approche pourrait être:

  1. Supprimer AN à partir de la première fram de données

  2. Utilisation rbind pour ajouter les données au lieu d'utiliser fusion:

Ce sont les deux originaux trames de données:

foo <- data.frame(index=c('a', 'b', 'c', 'd'), value=c(100, 101, NA, NA)) 
bar <- data.frame(index=c('c', 'd'), value=c(200, 201)) 

(1) utiliser le négation de is.na pour éliminer les NAs:

foo_new <- foo[!is.na(foo$value),] 

(2) Liez les trames de données et vous obtiendrez la réponse que vous cherchiez

new_df <- rbind(foo_new,bar) 

      new_df 
      index value 
      1  a 100 
      2  b 101 
      3  c 200 
      4  d 201 
0

Je pense que le moyen le plus simple est de "marquer" la valeur qui doit être mise à jour avant la fusion.

bar$update <- TRUE 
foo <- merge(foo, bar, by='index', all=T, suffixes=c("",".update")) 
foo[!is.na(foo$update),]$value <- foo[!is.na(foo$update),]$value.update 
foo$value.update <- NULL 
foo$update <- NULL 

Il serait plus rapide en utilisant 'data.table'

library(data.table) 
foo <- as.data.table(foo) 
bar <- as.data.table(bar) 
bar[, update:=TRUE] 
foo <- merge(foo, bar, by='index', all=T, suffixes=c("",".update")) 
foo[!is.na(update),value:=value.update] 
foo[, c("value.update","update"):=NULL] 
foo 

    index value 
1:  a 100 
2:  b 101 
3:  c 200 
4:  d 201 
Questions connexes