Boucle pour créer une variable à partir des valeurs/modalités de deux autres

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

Augustin Zindel
Messages : 6
Enregistré le : 19 Sep 2019, 12:17

Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Augustin Zindel » 19 Sep 2019, 13:49

Bonjour à tous,

Je suis débutant sur R et voici mon objectif : Créer une variable V2, qui prend pour valeur, pour chaque modalité de la variable N (20 modalités de A à T), la différence entre les deux dernières valeurs de la variable V1 ( valeur(i-2) - valeur (i-1) ) pour la modalité de N en question.
Pour être au maximum clair, je vous joins un tableau pour exemple avec 2 modalités de N.
N V1 V2
1 A 6 NA
2 B 5 NA
3 A 8 NA
4 B 7 NA
5 A 4 6-8=-2
6 B 5 5-7=-2
7 A 2 8-4=+4
8 B 1 7-5=+2
9 A 9 2-9=-7
10 B 1 5-1=+4

J'ai essayé un code de boucle, qui me semble assez compliqué et il y a plusieurs erreurs...

Merci à vous pour votre aide,
Augustin.

Michaël Delorme
Messages : 67
Enregistré le : 04 Avr 2016, 10:21

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Michaël Delorme » 19 Sep 2019, 15:24

Si j'ai bien compris (une erreur à la ligne 9 ?)...
Avec lag et des données groupées sur N :

Code : Tout sélectionner

library(tidyverse)
donnees <- read_delim("id N V1 V2
1 A 6 NA
2 B 5 NA
3 A 8 NA
4 B 7 NA
5 A 4 6-8=-2
6 B 5 5-7=-2
7 A 2 8-4=+4
8 B 1 7-5=+2
9 A 9 2-9=-7
10 B 1 5-1=+4", delim = " ")

donnees %>%
  group_by(N) %>%
  mutate(V3 = lag(V1, 2) - lag(V1))


ce qui donne :

Code : Tout sélectionner

# A tibble: 10 x 5
# Groups:   N [2]
      id N        V1 V2        V3
   <dbl> <chr> <dbl> <chr>  <dbl>
 1     1 A         6 NA        NA
 2     2 B         5 NA        NA
 3     3 A         8 NA        NA
 4     4 B         7 NA        NA
 5     5 A         4 6-8=-2    -2
 6     6 B         5 5-7=-2    -2
 7     7 A         2 8-4=+4     4
 8     8 B         1 7-5=+2     2
 9     9 A         9 2-9=-7     2
10    10 B         1 5-1=+4     4

Eric Casellas
Messages : 767
Enregistré le : 06 Jan 2009, 14:59

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Eric Casellas » 19 Sep 2019, 15:27

Bonjour,

Il n'y a pas de question mais voici une proposition de code avec les fonctions de base :

Code : Tout sélectionner

X <- data.frame(N=sample(LETTERS[1:2], 10, replace=TRUE),
                V1=sample.int(10, replace=TRUE),
                V2=NA)

for (case in levels(X$N)) {
  xdata <- X[as.character(X$N)==case,]
  for (i in 3:nrow(xdata)) {
    xdata$V2[i] <- xdata$V1[i-2] - xdata$V1[i-1]
  }
  X[as.character(X$N)==case,]$V2 <- xdata$V2
}


Eric
Eric

Augustin Zindel
Messages : 6
Enregistré le : 19 Sep 2019, 12:17

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Augustin Zindel » 20 Sep 2019, 14:01

Michaël Delorme a écrit :Si j'ai bien compris (une erreur à la ligne 9 ?)...
Avec lag et des données groupées sur N :

Code : Tout sélectionner

library(tidyverse)
donnees <- read_delim("id N V1 V2
1 A 6 NA
2 B 5 NA
3 A 8 NA
4 B 7 NA
5 A 4 6-8=-2
6 B 5 5-7=-2
7 A 2 8-4=+4
8 B 1 7-5=+2
9 A 9 2-9=-7
10 B 1 5-1=+4", delim = " ")

donnees %>%
  group_by(N) %>%
  mutate(V3 = lag(V1, 2) - lag(V1))


ce qui donne :

Code : Tout sélectionner

# A tibble: 10 x 5
# Groups:   N [2]
      id N        V1 V2        V3
   <dbl> <chr> <dbl> <chr>  <dbl>
 1     1 A         6 NA        NA
 2     2 B         5 NA        NA
 3     3 A         8 NA        NA
 4     4 B         7 NA        NA
 5     5 A         4 6-8=-2    -2
 6     6 B         5 5-7=-2    -2
 7     7 A         2 8-4=+4     4
 8     8 B         1 7-5=+2     2
 9     9 A         9 2-9=-7     2
10    10 B         1 5-1=+4     4


Merci Mickaël et Eric pour vos réponses.
En effet Mickaël, il y a bien une erreur à la ligne 9 : A =4-2.
J'ai essayé les deux codes que vous me proposez, en essayant de les adapter à mon dataframe.
Je voudrais avant-tout donner 2 précisions : j'ai simplifié les choses pour l'exemple, mon dataframe contient 760 observations et les modalités de N sont 20 mots.

Pour le code de Mickaël : Avec les 760 observations et les 30aines de variables donc il m'est impossible de reporter les colonnes dans le 1er argument entre guillemets.... J'ai essayé de changer en mettant

Code : Tout sélectionner

donnees <- read_delim("N","V1", delim = " ")
mais j'ai une erreur de type "Error in eval(lhs, parent, parent) : object 'donnees' not found" qui est apparue, je pense parce que j'ai mis 2 arguments et qu'il en faut un seul. Vois-tu une solution, sans copier les colonnes et leurs valeurs dans le code ?

Pour celui d'Eric :
Je pense que l'argument

Code : Tout sélectionner

X <- data.frame(V1=sample(LETTERS[1:2], 760, replace=TRUE)
LETTERS[1:2] bloque car du coup il ne renvoie que 2 lettres ("A" et "B") dans le nouveau dataframe X, or N contient 20 mots. Il faudrait un argument qui puisse le remplacer par un argument qui dise "Chacun des 20 mots que contient N". J'ai essayé avec l'argument "words" mais cela ne marche pas... Est-ce que tu vois une solution ?

Merci à vous pour vos réponses,
Augustin

Michaël Delorme
Messages : 67
Enregistré le : 04 Avr 2016, 10:21

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Michaël Delorme » 20 Sep 2019, 14:27

la partie du code avec read_delim n'est pas nécessaire (je l'ai mise pour avoir un exemple reproductible). Tout ce dont tu as besoin c'est (si ton dataframe s'appelle "donnees", ta colonne de regroupement "N" et tes valeurs "V1") :

Code : Tout sélectionner

library(tidyverse)
donnees %>%
  group_by(N) %>%
  mutate(V2 = lag(V1, 2) - lag(V1))


Cordialement

Eric Casellas
Messages : 767
Enregistré le : 06 Jan 2009, 14:59

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Eric Casellas » 20 Sep 2019, 14:43

Augustin Zindel a écrit :Pour celui d'Eric :
Je pense que l'argument

Code : Tout sélectionner

X <- data.frame(V1=sample(LETTERS[1:2], 760, replace=TRUE)
LETTERS[1:2] bloque car du coup il ne renvoie que 2 lettres ("A" et "B") dans le nouveau dataframe X, or N contient 20 mots. Il faudrait un argument qui puisse le remplacer par un argument qui dise "Chacun des 20 mots que contient N". J'ai essayé avec l'argument "words" mais cela ne marche pas... Est-ce que tu vois une solution ?

Merci à vous pour vos réponses,
Augustin


Dans mon code cette partie était pour générer (aléatoirement par tirage via la fonction sample) les données de départ.
Donc soit tu pars directement de tes données existantes, soit tu peut changer le nombre de cas générés différents en changeant la valeur des choix possibles (par exemple pour avoir les 20 première lettre remplacer LETTERS[1:2] par LETTERS[1:20])

Eric
Eric

Augustin Zindel
Messages : 6
Enregistré le : 19 Sep 2019, 12:17

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Augustin Zindel » 20 Sep 2019, 16:57

Eric Casellas a écrit :Dans mon code cette partie était pour générer (aléatoirement par tirage via la fonction sample) les données de départ.
Donc soit tu pars directement de tes données existantes, soit tu peut changer le nombre de cas générés différents en changeant la valeur des choix possibles (par exemple pour avoir les 20 première lettre remplacer LETTERS[1:2] par LETTERS[1:20])

Eric

Eric :
Ah d'accord, je retiens pour le tirage aléatoire. Donc oui je souhaite partir de mes modalités existantes de V1 (catégorielle à 20 modalités). J'ai essayé ce code-ci :

Code : Tout sélectionner

X <- data.frame(N=sample(levels(donnees$N), 760, replace=TRUE),
                V1=sample.int(760, replace=TRUE),
                V2=NA)

for (case in levels(X$N)) {
  xdata <- X[as.character(X$N)==case,]
  for (i in 3:nrow(xdata)) {
    xdata$V2[i] <- xdata$V1[i-2] - xdata$V1[i-1]
  }
  X[as.character(X$N)==case,]$V2 <- xdata$V2
}


Je n'ai pas de message d'erreur. Mais j'obtiens le dataframe xdata avec 39 observations seulement au lieu de 760 (car correspond à toutes les observations mais pour une seule des modalités de N), des valeurs de V1 complètement modifiées (positives seulement, allant jusqu'à 730 et quelques) et des valeurs de V2 allant jusqu'à 640. V1 contient des valeurs comprises normalement entre 1 et 20.
Alors que rentrer comme 1er argument à la première ligne de ton code, où j'ai mis "levels(donnees$N) ? Ou le problème vient-il d'ailleurs ?

Mickaël:

la partie du code avec read_delim n'est pas nécessaire (je l'ai mise pour avoir un exemple reproductible). Tout ce dont tu as besoin c'est (si ton dataframe s'appelle "donnees", ta colonne de regroupement "N" et tes valeurs "V1") :

Code : Tout sélectionner

library(tidyverse)
donnees %>%
  group_by(N) %>%
  mutate(V2 = lag(V1, 2) - lag(V1))



J'ai effectué exactement ce que tu m'as indiqué de faire. Pas de message d'erreur, cela me sort, dans la console, un tableau en résultat avec # ... with 750 more rows, and 1 more variable: V3 <dbl> mais je ne sais pas comment accéder à cette variable V3 qui n'est pas affichée dans ce tableau. De plus, la variable V3 n'est pas ajoutée à mon dataframe donc je n'ai aucune lisibilité dessus et j'aimerais quelle y soit intégrée. Comment faire ?

Merci pour vos réponses,
Bonne fin de journée,
Augustin.

Eric Casellas
Messages : 767
Enregistré le : 06 Jan 2009, 14:59

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Eric Casellas » 23 Sep 2019, 07:10

Augustin Zindel a écrit :
Eric Casellas a écrit :Dans mon code cette partie était pour générer (aléatoirement par tirage via la fonction sample) les données de départ.
Donc soit tu pars directement de tes données existantes, soit tu peut changer le nombre de cas générés différents en changeant la valeur des choix possibles (par exemple pour avoir les 20 première lettre remplacer LETTERS[1:2] par LETTERS[1:20])

Eric

Eric :
Ah d'accord, je retiens pour le tirage aléatoire. Donc oui je souhaite partir de mes modalités existantes de V1 (catégorielle à 20 modalités). J'ai essayé ce code-ci :

Code : Tout sélectionner

X <- data.frame(N=sample(levels(donnees$N), 760, replace=TRUE),
                V1=sample.int(760, replace=TRUE),
                V2=NA)

for (case in levels(X$N)) {
  xdata <- X[as.character(X$N)==case,]
  for (i in 3:nrow(xdata)) {
    xdata$V2[i] <- xdata$V1[i-2] - xdata$V1[i-1]
  }
  X[as.character(X$N)==case,]$V2 <- xdata$V2
}


Je n'ai pas de message d'erreur. Mais j'obtiens le dataframe xdata avec 39 observations seulement au lieu de 760 (car correspond à toutes les observations mais pour une seule des modalités de N), des valeurs de V1 complètement modifiées (positives seulement, allant jusqu'à 730 et quelques) et des valeurs de V2 allant jusqu'à 640. V1 contient des valeurs comprises normalement entre 1 et 20.
Alors que rentrer comme 1er argument à la première ligne de ton code, où j'ai mis "levels(donnees$N) ? Ou le problème vient-il d'ailleurs ?


Je ne suis pas sûr de ce que tu veux faire mais à priori j'aurais dis que tu devrais plutôt remplacer dans mon code l'objet X par ton donnees et donc tu n'as pas à construire l'objet X via sample (par contre dans mon exemple la colonne N est un factor et pas un character, je ne sais pas ce que tu as de ton coté...)

Eric
Eric

Augustin Zindel
Messages : 6
Enregistré le : 19 Sep 2019, 12:17

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Augustin Zindel » 23 Sep 2019, 09:11

Eric Casellas a écrit :
Je ne suis pas sûr de ce que tu veux faire mais à priori j'aurais dis que tu devrais plutôt remplacer dans mon code l'objet X par ton donnees et donc tu n'as pas à construire l'objet X via sample (par contre dans mon exemple la colonne N est un factor et pas un character, je ne sais pas ce que tu as de ton coté...)

Eric


Bonjour Eric,

Si je pense que tu as compris ce que je voulais faire (calculer la différence i-2 - i-1 (des 2 dernières observations) de la variable V1 pour chacune des 20 modalités de ma variable N.
J'ai essayé de faire comme tu m'as dit, j'ai changé le code pour :

Code : Tout sélectionner

for (case in levels(donnees$N)) {
  xdata <- donnees[as.factor(donnees$N)==case,]
  for (i in 760:nrow(xdata)) {
    xdata$V2[i] <- xdata$V1[i-2] - xdata$V1[i-1]
  }
  donnees[as.factor(donnees$N)==case,]$V2 <- xdata$V2
}

En changeant du coup as.character par as.factor vu que N est en as.factor (bonne idée ou non?). J'ai dans mon dataframe 760 observations et R me renvoit le message d'erreur suivant:

Code : Tout sélectionner

 Error in `$<-.data.frame`(`*tmp*`, "V2", value = c(NA_real_, NA_real_,  : replacement has 760 rows, data has 38

j'ai 38 observations pour chacune des modalités de ma variable N donc je pense que R ne prend en compte qu'une seule de ces modalités (problème à la ligne " xdata <- donnees[as.factor(donnees$N)==case,]" on donne qu'une seule modalité de N dans xdata non ?

Bonne fin de matinée,
Augustin.

Eric Casellas
Messages : 767
Enregistré le : 06 Jan 2009, 14:59

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Eric Casellas » 23 Sep 2019, 09:42

Augustin Zindel a écrit :Bonjour Eric,

Si je pense que tu as compris ce que je voulais faire (calculer la différence i-2 - i-1 (des 2 dernières observations) de la variable V1 pour chacune des 20 modalités de ma variable N.
J'ai essayé de faire comme tu m'as dit, j'ai changé le code pour :

Code : Tout sélectionner

for (case in levels(donnees$N)) {
  xdata <- donnees[as.factor(donnees$N)==case,]
  for (i in 760:nrow(xdata)) {
    xdata$V2[i] <- xdata$V1[i-2] - xdata$V1[i-1]
  }
  donnees[as.factor(donnees$N)==case,]$V2 <- xdata$V2
}

En changeant du coup as.character par as.factor vu que N est en as.factor (bonne idée ou non?). J'ai dans mon dataframe 760 observations et R me renvoit le message d'erreur suivant:

Code : Tout sélectionner

 Error in `$<-.data.frame`(`*tmp*`, "V2", value = c(NA_real_, NA_real_,  : replacement has 760 rows, data has 38

j'ai 38 observations pour chacune des modalités de ma variable N donc je pense que R ne prend en compte qu'une seule de ces modalités (problème à la ligne " xdata <- donnees[as.factor(donnees$N)==case,]" on donne qu'une seule modalité de N dans xdata non ?

Bonne fin de matinée,
Augustin.



Il y a plusieurs soucis dans ton adaptation de mon code:

- Si ta colonne N n'est pas déjà de type factor il faut remplacer levels(donnees$N) par levels(as.factor(donnees$N)) et as.factor(donnees$N)==case par donnees$N==case
- Dans la 2eme boucle for il faut laisser 3:nrow(xdata)

Eric
Eric

Augustin Zindel
Messages : 6
Enregistré le : 19 Sep 2019, 12:17

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Augustin Zindel » 23 Sep 2019, 12:39

Si si, ma colonne N est en facteur de 20 modalités. Quand je remplace le code par 3:nrow(xdata), j'ai le même message d'erreur " Error in`$<-.data.frame`(`*tmp*`, "V2", value = c(NA, NA, -3)) : replacement has 3 rows, data has 38 ". Donc en fait R comprend qu'il y a 38 observations (nombre d'observations pour 1 seule des 20 modalités de N).
J'ai donc ce code là :

Code : Tout sélectionner

for (case in levels(donnees$N)) {
  xdata <- donnees[as.factor(donnees$N)==case,]
  for (i in 3:nrow(xdata)) {
    xdata$V2[i] <- xdata$V1[i-2] - xdata$V1[i-1]
  }
  donnees[as.factor(donnees$N)==case,]$V2 <- xdata$V2
}

J'ai essayé d'enlever le as.factor dans le code, mais ça ne marche pas et j'ai le même message d'erreur.

Augustin

Eric Casellas
Messages : 767
Enregistré le : 06 Jan 2009, 14:59

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Eric Casellas » 23 Sep 2019, 13:28

Si ta colonne est déjà de type factor alors tu peut ne pas mettre les as.factor et comparer directement match$HomeTeam==case.

Et sinon dans l'exemple que je t'ai donné on a déjà avant le début de la boucle initialisé la colonne V2 avec des NA partout, c'est peut-être ça qui te manque?

Code : Tout sélectionner

match$V2 <- NA


Eric
Eric

Augustin Zindel
Messages : 6
Enregistré le : 19 Sep 2019, 12:17

Re: Boucle pour créer une variable à partir des valeurs/modalités de deux autres

Messagepar Augustin Zindel » 23 Sep 2019, 17:53

Oui exactement c'est ce qu'il manquait juste avant ! Le code marche maintenant !
Je remets donc l'exemple de code complet pour celles et ceux qui auraient besoin :

Code : Tout sélectionner

donnees$V2 <- NA
for (case in levels(donnees$N)) {
  xdata <- donnees[(donnees$N)==case,]
  for (i in 3:nrow(xdata)) {
    xdata$V2[i] <- xdata$V1[i-2] - xdata$V1[i-1]
  }
  donnees[(donnees$N)==case,]$V2 <- xdata$V2
}


J'ai une dernière questions: Soit une deuxième colonne nommée O, qui a les mêmes 20 modalités que la colonne N, dans un ordre différent et une variable W1 avec les valeurs de chaque modalité de la colonne O. Si je veux que V2 soit la différence des 2 dernières valeurs observées de chacune des modalités sur les deux colonnes N et O (et des valeurs associées aux colonnes V1 et W1), que dois-je changer dans mon code ?

Je t'en remercie Eric pour toutes tes réponses et ton aide précieuse !
Augustin


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Google [Bot] et 1 invité

cron