Boucle

Postez ici vos questions, réponses, commentaires ou suggestions - Les sujets seront ultérieurement répartis dans les archives par les modérateurs

Modérateur : Groupe des modérateurs

Anais Payen
Messages : 60
Enregistré le : 25 Fév 2019, 08:50

Boucle

Messagepar Anais Payen » 27 Mar 2019, 13:47

Bonjour,

J'ai actuellement 2 data.frame et je souhaiterai faire une correspondance, et un remplissage automatique de ma nouvelle colonne lorsqu'il y a une correspondance, sans utiliser un merge.
Mais comme d'habitude, ma boucle ne fonctionne pas...

Voici mon df1 :

Code : Tout sélectionner

          cip13    cip7 ucd13 ucd7                                             nom_court
1 3400930000649 3000064         NA                              A 313 50000UI CAPSULE 30
2 3400930001479 3000147         NA       A 313 A LA TYROTHRICINE POMMADE TUBE 50G 1/50 G
3 3400930139448 3013944         NA                          ABACAVIR MYLAN 300 MG 60 CPR
4 3400930089958 3008995         NA                         ABACAVIR SANDOZ 300 MG CPR 60
5 3400930059968 3005996         NA                  ABACAVIR/LAM EG 600 MG/300 MG CPR 30
6 3400930076972 3007697         NA ABACAVIR/LAMIVUDINE AUTHOU 600 MG/300 MG 30 COMPRIMES



et mon df2 :

Code : Tout sélectionner

           nir_ano_17   eta_num rsa_num adm_nbr   ucd_ucd_cod
115 AD8PBPXEDQK4BUJ6D 590782165    7294       2 3400893475966
116 AD8PBPXEDQK4BUJ6D 590782165    7459       2 3400893475966
117 PW59HFBD670XD80XD 590782165    9586       3 3400893001813
118 XJ1XUAZUFAZCMGWWD 590782165    9593       1 3400893287880
119 XJ1XUAZUFAZCMGWWD 590782165    9593       6 3400893287880
120 WM0JC1XK21WNHZX1D 590782165    9959       1 3400893843734


Je recherche donc des correspondances entre mes colonnes ucd13 ou ucd7 de mon df1, et ma colonne ucd_ucd_ucd de mon df2.

Cette formule :

Code : Tout sélectionner

MCO_D[133,6] <- CIP[which(CIP[,4] %in% MCO_D[133,5]),5]
me permet de trouver une correspondance, j'ai donc essayé cette boucle :

Code : Tout sélectionner

for (i in 1:353) {
  if ((CIP[which(CIP[,4] %in% MCO_D[i,5]),5]) != 0)
  {MCO_D[i,6] <- CIP[which(CIP[,4] %in% MCO_D[i,5]),5] }
  else {MCO_D[i,6]<-0}
}


J'ai utilisé les chiffres 0 car il est possible que je n'ai aucune correspondance, mon df1 n'étant pas terminé.

L'un d'entre vous aurait il une idée pour corriger ma boucle?

Merci d'avance,

Anaïs

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: Boucle

Messagepar Mickael Canouil » 27 Mar 2019, 15:25

Bonjour,

votre exemple requiert trop de manutention pour être utile, notamment à cause des espaces dans la colonne nom_court par exemple.
votre df1 c'est MCO_D et df2 CIP ? L'inverse ? Autre-chose ?
A vu d'oeil, dans votre exemple, il n'y a aucune correspondance entre df1 et df2 sur les colonnes que vous mentionnez.
Pourquoi ne pas vouloir utiliser merge, qui répond pourtant à votre problématique ?

Qu'est-ce qu'un code reproductible ?
Comment insérer des données dans un message ?

Anais Payen a écrit :

Code : Tout sélectionner

for (i in 1:353) {
  if ((CIP[which(CIP[,4] %in% MCO_D[i,5]),5]) != 0)
  {MCO_D[i,6] <- CIP[which(CIP[,4] %in% MCO_D[i,5]),5] }
  else {MCO_D[i,6]<-0}
}


Une autre suggestion de lecture => https://style.tidyverse.org/syntax.html#indenting
Autre remarque, vous devriez utilisez les noms des colonnes en lieu et place des indices, qui ici nuit considérablement à la compréhension du code et la reproductibilité.

Cordialement,
Mickaël
mickael.canouil.fr | rlille.fr

Anais Payen
Messages : 60
Enregistré le : 25 Fév 2019, 08:50

Re: Boucle

Messagepar Anais Payen » 27 Mar 2019, 15:55

Bonjour,

Excusez moi pour mon manque de précision, le df1 = CIP et le df2 = MCO_D.

Je n'ai affiché que les 5 premières lignes de mes 2 df car ils contiennent chacun plus de 20.000 lignes.
Je ne peux pas utiliser merge car mes scripts sont relus, et la fonction merge ne peut pas être vérifiée et semble parfois présenter quelques erreurs...

Autre remarque, vous devriez utilisez les noms des colonnes en lieu et place des indices, qui ici nuit considérablement à la compréhension du code et la reproductibilité.


Débutante sur R, je n'ai pas compris ce que vous vouliez que je fasse avec mes intitulés..

Merci pour votre réponse!

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: Boucle

Messagepar Mickael Canouil » 27 Mar 2019, 16:56

Avec un exemple reproductible:

Soit deux data.frame df1 et df2

Code : Tout sélectionner

library(tibble)
set.seed(20190327)

df1 <- rbind(iris, dplyr::mutate(iris, Species = paste0(Species, "_bis")))
head(df1)
#>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1          5.1         3.5          1.4         0.2  setosa
#> 2          4.9         3.0          1.4         0.2  setosa
#> 3          4.7         3.2          1.3         0.2  setosa
#> 4          4.6         3.1          1.5         0.2  setosa
#> 5          5.0         3.6          1.4         0.2  setosa
#> 6          5.4         3.9          1.7         0.4  setosa
df2 <- as.data.frame(tibble::tibble(
  Species = c(levels(iris$Species), LETTERS),
  random_values = rnorm(n = length(Species))
))
head(df2)
#>      Species random_values
#> 1     setosa    1.08706917
#> 2 versicolor   -0.12446316
#> 3  virginica   -1.00227336
#> 4          A    0.17239623
#> 5          B   -0.01359735
#> 6          C   -1.10421747


Votre solution (légèrement modifiée) avec les indices des colonnes

Code : Tout sélectionner

df1[, 6] <- 0
for (irow in 1:nrow(df1)) {
  if (df1[irow, 5] %in% df2[, 1]) {
    df1[irow, 6] <- df2[df2[, 1] %in% df1[irow, 5], 2]
  }
}
head(df1)
#>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species       V6
#> 1          5.1         3.5          1.4         0.2  setosa 1.087069
#> 2          4.9         3.0          1.4         0.2  setosa 1.087069
#> 3          4.7         3.2          1.3         0.2  setosa 1.087069
#> 4          4.6         3.1          1.5         0.2  setosa 1.087069
#> 5          5.0         3.6          1.4         0.2  setosa 1.087069
#> 6          5.4         3.9          1.7         0.4  setosa 1.087069


La même solution avec les noms des colonnes

Code : Tout sélectionner

df1[, "values_from_df2"] <- 0
for (irow in 1:nrow(df1)) {
  if (df1[irow, "Species"] %in% df2[, "Species"]) {
    df1[irow, "values_from_df2"] <- df2[df2[, "Species"] %in% df1[irow, "Species"], "random_values"]
  }
}
head(df1)
#>   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
#> 1          5.1         3.5          1.4         0.2  setosa
#> 2          4.9         3.0          1.4         0.2  setosa
#> 3          4.7         3.2          1.3         0.2  setosa
#> 4          4.6         3.1          1.5         0.2  setosa
#> 5          5.0         3.6          1.4         0.2  setosa
#> 6          5.4         3.9          1.7         0.4  setosa
#>   values_from_df2
#> 1        1.087069
#> 2        1.087069
#> 3        1.087069
#> 4        1.087069
#> 5        1.087069
#> 6        1.087069


Quelle est la version la plus claire ?

Maintenant, si on compare un merge avec la boucle:

Code : Tout sélectionner

df1[, "values_from_df2"] <- 0
for (irow in 1:nrow(df1)) {
  if (df1[irow, "Species"] %in% df2[, "Species"]) {
    df1[irow, "values_from_df2"] <- df2[df2[, "Species"] %in% df1[irow, "Species"], "random_values"]
  }
}
head(unique(df1[, c("Species", "values_from_df2")]))
#>            Species values_from_df2
#> 1           setosa       1.0870692
#> 51      versicolor      -0.1244632
#> 101      virginica      -1.0022734
#> 151     setosa_bis       0.0000000
#> 201 versicolor_bis       0.0000000
#> 251  virginica_bis       0.0000000

Code : Tout sélectionner

res_merge <- merge(x = df1, y = df2, by = "Species", all.x = TRUE, all.y = FALSE)
head(unique(res_merge[, c("Species", "values_from_df2")]))
#>            Species values_from_df2
#> 1           setosa       1.0870692
#> 51      versicolor      -0.1244632
#> 101      virginica      -1.0022734
#> 151     setosa_bis       0.0000000
#> 201 versicolor_bis       0.0000000
#> 251  virginica_bis       0.0000000

C'est exactement le même résultat, si ce n'est pas bon, ce n'est pas merge le responsable.
Il vous faut donc bien définir les arguments et là je vous renvoie vers l'aide de la fonction.

Si on compare en terme de performance, clairement le merge fait beaucoup mieux (27.5 fois mieux ici):

Code : Tout sélectionner

benchr::benchmark(
  "for" = {
    df1[, "values_from_df2"] <- 0
    for (irow in 1:nrow(df1)) {
      if (df1[irow, "Species"] %in% df2[, "Species"]) {
        df1[irow, "values_from_df2"] <- df2[df2[, "Species"] %in% df1[irow, "Species"], "random_values"]
      }
    }
  },
  "merge" = {
    res_merge <- merge(x = df1, y = df2, by = "Species", all.x = TRUE, all.y = FALSE)
  }
)
#> Benchmark summary:
#> Time units : microseconds
#>   expr n.eval   min lw.qu median  mean up.qu   max   total relative
#>    for    100 24700 25900  26700 27000 28000 33400 2700000     27.5
#>  merge    100   882   934    971   993  1010  3080   99300      1.0


Cordialement,
Mickaël
mickael.canouil.fr | rlille.fr

Anais Payen
Messages : 60
Enregistré le : 25 Fév 2019, 08:50

Re: Boucle

Messagepar Anais Payen » 28 Mar 2019, 09:23

Merci pour votre temps et votre réponse, en lisant votre remarque à mon collègue, j'ai compris que vous parliez de l'intitulé des colonnes.

Vos exemples sont très clairs, mais en remplaçant avec mes arguments cela ne fonctionne pas. J'ai pourtant suivi votre exemple à la lettre.

Je sais que la fonction merge est très efficace.

Merci encore et bonne journée


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité

cron