Conditionnelle de fusion/de remplacement dans la R
J'ai deux trames de données:
df1
x1 x2
1 a
2 b
3 c
4 d
et
df2
x1 x2
2 zz
3 qq
Je veux remplacer certaines valeurs dans df1$x2 avec des valeurs dans df2$x2 basée sur la condition de correspondance entre df1$x1 et df2$x2 à produire:
Nice. J'ai écrit le match avec inversée arguments et ne comprenais pas pourquoi c'était plus compliqué que ce que je pensais qu'il devrait être. Je vais ajouter ma réponse, car il peut aider les autres à penser sur la façon dont le changement de l'ordre des arguments dans le match peut rendre les choses plus facile ou plus difficile. Merci Joris. Je travaillais avec le 'match', mais ne pouvait pas le faire fonctionner. J'ai ajouté une solution qui permettra de mieux performer dans le cas de non-valeurs uniques dans df1. thx, semble legit
Je vois que Joris et Aaron ont tous deux choisi de construire des exemples sans facteurs. Je peux certainement comprendre ce choix. Pour le lecteur avec des colonnes qui sont déjà des facteurs il y aurait aussi l'option de la contrainte de "caractère". Il y a une stratégie qui évite que la contrainte et ce qui permet également de la possibilité qu'il peut y avoir des indices dans df2 qui ne sont pas dans df1 qui, je crois, à invalider Joris Meys, mais pas Aarons solutions postées jusqu'à présent:
Il exige que les niveaux de l'être élargi pour inclure l'intersection des deux facteur de variables et puis aussi la nécessité de chute de non-correspondance des colonnes (= NA valeurs) dans le match(df1$x1, df2$x1)
Nice. Facteurs peut être difficile et les conseils pour développer le niveau est utile. Vous vous retrouvez avec une inutiles niveau df1$x2 bien (le xx). Si vous souhaitez supprimer ce sont maintenant inutiles niveaux, puis le faire: df1$x2 <- factor(df1$x2)
La première partie de Joris réponse est bonne, mais dans le cas de non-valeurs uniques dans df1, la ligne de sages-pour-la boucle ne sera pas à l'échelle sur des données de grande taille.les cadres.
Vous pouvez utiliser un data.table de mise à jour "join" pour modifier en place, ce qui sera très rapide:
library(data.table)
setDT(df1); setDT(df2)
df1[df2, on = .(x1), x2 := i.x2]
Ou, en supposant que vous n'avez pas de soins sur le maintien de la ligne de commande, vous pouvez utiliser SQL-inspiré dplyr:
library(dplyr)
union_all(
inner_join( df1["x1"], df2 ),# x1 from df1 with matches in df2, x2 from df2
anti_join( df1, df2["x1"])# rows of df1 with no match in df2)# %>% arrange(x1) # optional, won't maintain an arbitrary row order
L'une de ces solutions à l'échelle beaucoup mieux que la ligne de sages-pour-boucle.
Les données.tableau idiome est df1[df2, on=.(x1), x2 := i.x2 ] -- modifie en place ("remplacer certaines valeurs dans df1$x2", comme l'OP demande) et ne nécessite pas de configuration des touches. Il est semblable à une mise à jour rejoindre à partir de SQL. yep vous me battre pour elle. Ok. df1[df2, x2 := df2[,x2]] n'est pas la même chose, pour info. ressemble Hadley a décidé de ne pas pour mettre en œuvre mise à jour de la rejoindre dans dplyr, ce qui semble être une faiblesse dans le paquet pour moi. Ouais, j'ai vu qu'. Hadley est une raison d'exclusion est assez faible (disant qu'il s'agit de coller à la pure SQL), depuis la mise à jour se joint à exister dans certaines saveurs de SQL. Il vient juste à la "grammaire" il est venu avec de ne pas être assez souple.
Vous pouvez le faire par correspondance dans l'autre sens aussi, mais c'est plus compliqué. Joris de la solution est mieux, mais je suis en train de mettre cela ici aussi comme un rappel à réfléchir sur la façon dont vous voulez faire correspondre.
df1 <- data.frame(x1=1:4, x2=letters[1:4], stringsAsFactors=FALSE)
df2 <- data.frame(x1=2:3, x2=c("zz","qq"), stringsAsFactors=FALSE)
swap <- df2$x2[match(df1$x1, df2$x1)]
ok <-!is.na(swap)
df1$x2[ok]<- swap[ok]> df1
x1 x2
11 a
22 zz
33 qq
44 d
utilisation
match()
, en supposant que les valeurs en df1 sont uniques.Si les valeurs ne sont pas uniques, utilisation :
Merci Joris. Je travaillais avec le 'match', mais ne pouvait pas le faire fonctionner.
J'ai ajouté une solution qui permettra de mieux performer dans le cas de non-valeurs uniques dans df1.
thx, semble legit
OriginalL'auteur Joris Meys
Je vois que Joris et Aaron ont tous deux choisi de construire des exemples sans facteurs. Je peux certainement comprendre ce choix. Pour le lecteur avec des colonnes qui sont déjà des facteurs il y aurait aussi l'option de la contrainte de "caractère". Il y a une stratégie qui évite que la contrainte et ce qui permet également de la possibilité qu'il peut y avoir des indices dans df2 qui ne sont pas dans df1 qui, je crois, à invalider Joris Meys, mais pas Aarons solutions postées jusqu'à présent:
Il exige que les niveaux de l'être élargi pour inclure l'intersection des deux facteur de variables et puis aussi la nécessité de chute de non-correspondance des colonnes (= NA valeurs) dans le match(df1$x1, df2$x1)
df1$x2
bien (lexx
).Si vous souhaitez supprimer ce sont maintenant inutiles niveaux, puis le faire:
df1$x2 <- factor(df1$x2)
OriginalL'auteur 42-
La première partie de Joris réponse est bonne, mais dans le cas de non-valeurs uniques dans
df1
, la ligne de sages-pour-la boucle ne sera pas à l'échelle sur des données de grande taille.les cadres.Vous pouvez utiliser un
data.table
de mise à jour "join" pour modifier en place, ce qui sera très rapide:Ou, en supposant que vous n'avez pas de soins sur le maintien de la ligne de commande, vous pouvez utiliser SQL-inspiré
dplyr
:L'une de ces solutions à l'échelle beaucoup mieux que la ligne de sages-pour-boucle.
df1[df2, on=.(x1), x2 := i.x2 ]
-- modifie en place ("remplacer certaines valeurs dans df1$x2", comme l'OP demande) et ne nécessite pas de configuration des touches. Il est semblable à une mise à jour rejoindre à partir de SQL.yep vous me battre pour elle.
Ok.
df1[df2, x2 := df2[,x2]]
n'est pas la même chose, pour info.ressemble Hadley a décidé de ne pas pour mettre en œuvre mise à jour de la rejoindre dans dplyr, ce qui semble être une faiblesse dans le paquet pour moi.
Ouais, j'ai vu qu'. Hadley est une raison d'exclusion est assez faible (disant qu'il s'agit de coller à la pure SQL), depuis la mise à jour se joint à exister dans certaines saveurs de SQL. Il vient juste à la "grammaire" il est venu avec de ne pas être assez souple.
OriginalL'auteur C8H10N4O2
Vous pouvez le faire par correspondance dans l'autre sens aussi, mais c'est plus compliqué. Joris de la solution est mieux, mais je suis en train de mettre cela ici aussi comme un rappel à réfléchir sur la façon dont vous voulez faire correspondre.
OriginalL'auteur Aaron