Renommer un level de variable sous conditions

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

Mallard Rémi
Messages : 3
Enregistré le : 13 Nov 2018, 15:39

Renommer un level de variable sous conditions

Messagepar Mallard Rémi » 13 Nov 2018, 20:05

Bonjour,
Je me retrouve avec un problème que je n'arrive pas à résoudre.
Paul passe trois "Test" dont un "Retest", même chose pour Lucie et tous les suivant (nombreux...)
Je souhaite renommer le level "Test" de la variable "Version" qui pour chaque Id identique correspond à la Date la plus récente.
Dans l'exemple ci-dessous, il s'agit de différencier les deux levels de Version identiques pour Paul et les deux levels identiques pour Lucie en fonction de la Date. Je souhaite renommer "Testfin" le dernier test passer par chaque Id.

BDD <- data.frame(Id=c("Paul","Paul","Paul","Lucie","Lucie","Lucie"), Version=c("Test","Retest","Test","Test","Retest","Test"), Date=c("20-01-2018","23-01-2018","06-06-2018","05-02-2018","08-02-2018","13-04-2018"))
BDD$Date <- dmy(BDD$Date)

Une idée ?

François Bonnot
Messages : 463
Enregistré le : 10 Nov 2004, 15:19
Contact :

Re: Renommer un level de variable sous conditions

Messagepar François Bonnot » 14 Nov 2018, 07:52

Bonjour,
Je suppose qu'il ne s'agit pas de renommer le niveau d'un facteur (ce qu'on ferait avec levels(x)[i] <- ...), mais d'affecter une nouvelle valeur à un élément d'un objet de classe factor.
Cette opération provoque une erreur si le niveau du facteur n'existe pas déjà.
Une solution est de travailler plutôt sur des chaines de caractères, quitte à retransformer le résultat en facteur si nécessaire:

Code : Tout sélectionner

BDD$Version <- as.character(BDD$Version)
BDD.s <- split(BDD,BDD$Id)
li <- lapply(BDD.s,function(z) { z$Version[which.max(z$Date)] <- "Testfin" ; z} )
do.call(rbind,li)

Je pense qu'en utilisant ceratains packages on peut faire cette opération plus simplement, peut-être en un seule ligne.
François

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

Re: Renommer un level de variable sous conditions

Messagepar Mickael Canouil » 14 Nov 2018, 10:30

Bonjour,

Voici une petite simplification (explicitation) du code de François, pour combiner split/lapply:

Code : Tout sélectionner

do.call(
  what = "rbind",
  args = by(data = BDD, INDICES = BDD[["Id"]], FUN = function(.data) {
    .data[which.max(.data[["Date"]]), "Version"] <- "Testfin"
    return(.data)
  })
)


En version tidyverse (dplyr):

Code : Tout sélectionner

library(tidyverse)
BDD %>%
  dplyr::group_by(Id) %>%
  dplyr::mutate(Version = ifelse(test = Date==max(Date), yes = "Testfin", no = Version)) %>%
  dplyr::ungroup()


PS: Il aurait été bon de préciser que la fonction "dmy()" provenait du package lubridate ;)

Cordialement,
Mickaël

Mallard Rémi
Messages : 3
Enregistré le : 13 Nov 2018, 15:39

Re: Renommer un level de variable sous conditions

Messagepar Mallard Rémi » 14 Nov 2018, 11:53

François Bonnot a écrit :Bonjour,
Je suppose qu'il ne s'agit pas de renommer le niveau d'un facteur (ce qu'on ferait avec levels(x)[i] <- ...), mais d'affecter une nouvelle valeur à un élément d'un objet de classe factor.


Merci François, c'est tout a fait ça! Et ça fonctionne pour moi...
Par contre je n'ai pas utilisé la dernière partie do.call(rbind,li)

Code : Tout sélectionner

library(lubridate)
BDD <- data.frame(Id=c("Paul","Paul","Paul","Lucie","Lucie","Lucie"), Version=c("Test","Retest","Test","Test","Retest","Test"), Date=c("20-01-2018","23-01-2018","06-06-2018","05-02-2018","08-02-2018","13-04-2018"))
BDD$Date <- dmy(BDD$Date)

BDD$Version <- as.character(BDD$Version)
BDD.s <- split(BDD,BDD$Id)
BDD.s <- lapply(BDD.s,function(z) { z$Version[which.max(z$Date)] <- "Testfin" ; z} )
BDD <- unsplit(BDD.s,BDD$Id)                     
BDD$Version <- as.factor(BDD$Version)     


Et merci Mickael pour les deux autres propositions que je vais essayé de faire fonctionner.

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

Re: Renommer un level de variable sous conditions

Messagepar Mickael Canouil » 14 Nov 2018, 12:32

le "do.call(rbind,li)" est ici "équivalent" (un benchmark pourrait éventuellement dire le contraire) au "unsplit()".
Mickaël

Mallard Rémi
Messages : 3
Enregistré le : 13 Nov 2018, 15:39

Re: Renommer un level de variable sous conditions

Messagepar Mallard Rémi » 14 Nov 2018, 16:21

Mickael Canouil a écrit :le "do.call(rbind,li)" est ici "équivalent" (un benchmark pourrait éventuellement dire le contraire) au "unsplit()".


En fait j'ai parlé trop vite, "unsplit()" fonctionne sur cet échantillon de base de donnée mais pas sur la base de donnée réelles qui comporte plus d'une trentaine de colonnes alors que "do.call(rbind,li)" fonctionne sur la base de donnée complète.


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Christophe Genolini, Serge Rapenne et 1 invité