*

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

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

*

Messagepar Elsa Nario » 22 Mar 2019, 10:46

*

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

Re: Fonction ou macro

Messagepar Eric Casellas » 22 Mar 2019, 11:16

Bonjour,

Il ne me semble pas que la notion de macro existe avec les fonctions de base de R...

Après en ce qui concerne les fonction il y a des notions de visibilité des objets en fonction du contexte (https://cran.r-project.org/doc/manuals/R-lang.html#Environment-objects, https://adv-r.hadley.nz/environments.html), par exemple dans la fonction f que tu as mise, tu utilise un objet data qui n'est pas passé en argument donc il va utiliser celui d'un environnement de niveau supérieur. Par contre l'affectation que tu fait dans la fonction ne modifiera pas l'objet dans son environnement d'origine (tu peut utiliser l'opérateur <<- pour faire ça mais en général c'est déconseillé)

Un exemple de comment je ferais moi :

Code : Tout sélectionner

f <- function(df, x, varname) {
           df[, varname][!is.na(df$colA)) & !is.na(df$colB) & df$colA<=(x) & df$colB>=(x)] <- Ok
           return (df)
         }
         data <- f(data, 10, "var1")
         data <- f(data, 12, "var2")
         


Eric
Eric

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

*

Messagepar Elsa Nario » 22 Mar 2019, 13:47

*

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

*

Messagepar Elsa Nario » 25 Mar 2019, 07:54

*

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

Re: Fonction ou macro

Messagepar Mickael Canouil » 25 Mar 2019, 09:21

Bonjour,

A moins de nous donner les moyens de vous aider, nous ne pouvons pas deviner l'origine de votre problème en l'absence de code reproductible.
Comme déjà indiquer sur une autre de vos demandes.

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

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

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

*

Messagepar Elsa Nario » 25 Mar 2019, 10:50

*

Serge Rapenne
Messages : 1426
Enregistré le : 20 Aoû 2007, 15:17
Contact :

Re: Fonction ou macro

Messagepar Serge Rapenne » 25 Mar 2019, 13:28

Bonjour,

Une solution possible, c'est un peu "tordu" pour une débutante en R et il y a peut être plus simple mais ça fonctionne

Code : Tout sélectionner

l_seuil<-c(8,10,20,38) #la liste des seuils possibles
l_nom<-paste0("pres",1:4) #la liste des noms de colonne pour chaque seuil
don <- data.frame (debut=as.numeric(c(5, 6, 14, "", 34)), fin=as.numeric(c(12, 9, 30, 10,"")),
                   row.names=c("Nom1", "Nom2", "Nom3", "Nom4", "Nom5"))

FUN<-function(varname,x,dta){
  dta[,varname]<-as.numeric(!is.na(don$debut) & !is.na(don$fin) & don$debut<=x & don$fin>=x)
  return(dta)
}

Reduce(function(...) merge(..., all=T,sort=F),lapply(seq(l_seuil),function(x) FUN(l_nom[x],l_seuil[x],don)))

 debut fin pres1 pres2 pres3 pres4
1     5  12     1     1     0     0
2     6   9     1     0     0     0
3    14  30     0     0     1     0
4    NA  10     0     0     0     0
5    34  NA     0     0     0     0


Le principe : la fonction FUN ajoute une colonne a un df de nom varname contenant 1 si le test est vérifié et 0 sinon.
le lapply(seq(l_seuil),function(x) FUN(l_nom[x],l_seuil[x],don) produit une liste de df pour chaque valeur dans l_seuil et l_nom,
le Reduce(function(...) merge(..., all=T,sort=F), regroupe les élements de la liste en un seul df.

tu peux decomposer le déroulement du code comme ça :

Code : Tout sélectionner

FUN(l_nom[1],l_seuil[1],don)
   debut fin pres1
Nom1     5  12     1
Nom2     6   9     1
Nom3    14  30     0
Nom4    NA  10     0
Nom5    34  NA     0

lapply(1:4,function(x) FUN(l_nom[x],l_seuil[x],don))
[[1]]
     debut fin pres1
Nom1     5  12     1
Nom2     6   9     1
Nom3    14  30     0
Nom4    NA  10     0
Nom5    34  NA     0

[[2]]
     debut fin pres2
Nom1     5  12     1
Nom2     6   9     0
Nom3    14  30     0
Nom4    NA  10     0
Nom5    34  NA     0

[[3]]
     debut fin pres3
Nom1     5  12     0
Nom2     6   9     0
Nom3    14  30     1
Nom4    NA  10     0
Nom5    34  NA     0

[[4]]
     debut fin pres4
Nom1     5  12     0
Nom2     6   9     0
Nom3    14  30     0
Nom4    NA  10     0
Nom5    34  NA     0

#et enfin
Reduce(function(...) merge(..., all=T,sort=F),lapply(1:4,function(x) FUN(l_nom[x],l_seuil[x],don)))



Serge

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

Re: Fonction ou macro

Messagepar François Bonnot » 25 Mar 2019, 13:49

Bonjour,
Voici une fonction qui répond à la question d'origine, mais dont la syntaxe est un peu indigeste:

Code : Tout sélectionner

don <- data.frame (debut=as.numeric(c(5, 6, 14, "", 34)), fin=as.numeric(c(12, 9, 30, 10,"")),row.names=c("Nom1", "Nom2", "Nom3", "Nom4", "Nom5"))

f <- function(df, x, varname) {
    command <- paste0("df$",varname,"[!is.na(df$debut) & !is.na(df$fin) & df$debut<=",x," & df$fin>=",x,"] <- 1")
    eval(parse(text=command))
    df
}

f(don, 8, "pres1")


Si, comme dans la question de départ, on travaille toujours sur le même tableau "don", on peut utiliser à la rigueur :

Code : Tout sélectionner

don <- data.frame (debut=as.numeric(c(5, 6, 14, "", 34)), fin=as.numeric(c(12, 9, 30, 10,"")),row.names=c("Nom1", "Nom2", "Nom3", "Nom4", "Nom5"))

f2 <- function(x, varname) {
    command <- paste0("don$",varname,"[!is.na(don$debut) & !is.na(don$fin) & don$debut<=",x," & don$fin>=",x,"] <- 1")
    eval(parse(text=command),envir=parent.frame())
}

f2(8,"pres1")
don
François

Bastien Gamboa
Messages : 151
Enregistré le : 13 Jan 2011, 21:31

Re: Fonction ou macro

Messagepar Bastien Gamboa » 26 Mar 2019, 08:38

Bonjour,

Si le passage par une fonction n'est pas obligatoire, une boucle for() serait peut-être plus compréhensible :

Code : Tout sélectionner

don <- data.frame (debut=    as.numeric(c(5, 6, 14, "", 34)),
                   fin=      as.numeric(c(12, 9, 30, 10,"")),
                   row.names=c("Nom1", "Nom2", "Nom3", "Nom4", "Nom5"))
seuil <- c(8, 10, 20, 28) # Vecteur des seuils possible
for(i in 1:length(seuil)) {
  don[,paste0("pres", i)] <- ifelse(!is.na(don$debut) & !is.na(don$fin) & don$debut<=seuil[i] & don$fin>=seuil[i],
                                    1, 0) # Si la condition est rempli =1, sinon =0
}

HTH,
Bastien

Serge Rapenne
Messages : 1426
Enregistré le : 20 Aoû 2007, 15:17
Contact :

Re: Fonction ou macro

Messagepar Serge Rapenne » 26 Mar 2019, 08:54

@Bastien
Oui mais c'est beaucoup moins drôle ;-)

Serge

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Re: Fonction ou macro

Messagepar Logez Maxime » 26 Mar 2019, 09:53

Bonjour,

Si tu n'as pas besoin de conserver le résultat intermédiaire alors tu peux faire plus simple, sans se soucier du nom de la colonne dans laquelle sera stockée le résultat :

Code : Tout sélectionner

 mat <- sapply(seuil, function(x) (!is.na(don$debut) & ! is.na(don$fin) & don$debut <= x & don$fin >= x))
rowSums(mat)

# pour être plus efficace si jamais don devenait important en taille :
auxi <- !is.na(don$debut) & ! is.na(don$fin)
mat <- sapply(seuil, function(x) (auxi & don$debut <= x & don$fin >= x))
rowSums(mat)
Cordialement,
Maxime

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

Re: Fonction ou macro

Messagepar Mickael Canouil » 26 Mar 2019, 10:20

Bonjour,
Bastien Gamboa a écrit :

Code : Tout sélectionner

  don[,paste0("pres", i)] <- ifelse(!is.na(don$debut) & !is.na(don$fin) & don$debut<=seuil[i] & don$fin>=seuil[i],
                                    1, 0) # Si la condition est rempli =1, sinon =0

si je peux me permette, il me semble que TRUE fait toujours 1 et FALSE est toujours égal à zéro.
Le "ifelse()" est donc pas très utile, de même que la conversion de booléen à numérique.

Et un petit benchmark pour la route (avec conservation des résultats des tests logiques dans le data.frame):

Code : Tout sélectionner

benchr::benchmark(
  "Bastien" = {
    don <- data.frame(
      debut = as.numeric(c(5, 6, 14, "", 34)),
      fin = as.numeric(c(12, 9, 30, 10, "")),
      row.names = c("Nom1", "Nom2", "Nom3", "Nom4", "Nom5")
    )
    seuil <- c(8, 10, 20, 28) # Vecteur des seuils possible
   
   
    for (i in 1:length(seuil)) {
      don[, paste0("pres", i)] <- ifelse(!is.na(don$debut) & !is.na(don$fin) & don$debut <= seuil[i] & don$fin >= seuil[i],
        1, 0
      ) # Si la condition est rempli =1, sinon =0
    }
  },
  "Bastien_noif" = {
    don <- data.frame(
      debut = as.numeric(c(5, 6, 14, "", 34)),
      fin = as.numeric(c(12, 9, 30, 10, "")),
      row.names = c("Nom1", "Nom2", "Nom3", "Nom4", "Nom5")
    )
    seuil <- c(8, 10, 20, 28) # Vecteur des seuils possible
   
   
    for (i in 1:length(seuil)) {
      don[, paste0("pres", i)] <- !is.na(don$debut) & !is.na(don$fin) & don$debut <= seuil[i] & don$fin >= seuil[i]
    }
  },
  "Mickael" = {
    don <- data.frame(
      debut = as.numeric(c(5, 6, 14, "", 34)),
      fin = as.numeric(c(12, 9, 30, 10, "")),
      row.names = c("Nom1", "Nom2", "Nom3", "Nom4", "Nom5")
    )
    seuil <- c(8, 10, 20, 28) # Vecteur des seuils possible
   
   
    don[, paste0("seuil", seuil)] <- sapply(
      X = seuil, .don = don,
      FUN = function(iseuil, .don) {
        !is.na(.don$debut) & !is.na(.don$fin) &
          .don$debut <= iseuil & .don$fin >= iseuil
      }
    )
  },
  "Maxime" = {
    don <- data.frame(
      debut = as.numeric(c(5, 6, 14, "", 34)),
      fin = as.numeric(c(12, 9, 30, 10, "")),
      row.names = c("Nom1", "Nom2", "Nom3", "Nom4", "Nom5")
    )
    seuil <- c(8, 10, 20, 28) # Vecteur des seuils possible
   
   
    auxi <- !is.na(don$debut) & ! is.na(don$fin)
    don[, paste0("seuil", seuil)] <- sapply(
      X = seuil, .don = don, .auxi = auxi,
      FUN = function(iseuil, .don, .auxi) {
        .auxi &
          .don$debut <= iseuil & .don$fin >= iseuil
      }
    )
  }
)

Code : Tout sélectionner

#> Benchmark summary:
#> Time units : microseconds
#>          expr n.eval  min lw.qu median mean up.qu   max  total relative
#>       Bastien    100 7040  7210   7710 7820  8170 10600 782000    11.30
#>  Bastien_noif    100 6400  6740   6920 7370  7740 12000 737000    10.20
#>       Mickael    100  647   681    697  750   742  4720  75000     1.02
#>        Maxime    100  627   653    681  716   703  2710  71600     1.00


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

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Re: Fonction ou macro

Messagepar Logez Maxime » 26 Mar 2019, 10:47

Bonjour,

Si tu veux réellement comparer les différentes méthodes alors il ne faut pas inclure dans ton code tout ce qui concerne la création des objets, sinon la différence que tu observes n'est pas représentative des différences.
Sinon je partage ton avis sur les booléens un TRUE donne 1 et un FALSE donne 0 du moment qu'il est inclus dans une opération mathématique.
Si on a besoin de conserver les 0 ou les 1 alors deux possibilités :
i) on un objet plein de 0 et quand la condition est vérifiée on met 1
ii) on vérifie la condition et on utilise une opération mathématique pour transformer le booléen en entier (*1 ou +0, etc.).
On peut ainsi vérifier la condition sur tous les seuils, obtenir une matrice de booléen et la transformer en entier en une seule opération.

En général le ifelse peut se remplacer par des commandes plus efficaces en terme de temps de calcul, mais elle reste pratique à utiliser et facile à lire par la suite.

Si on n'a pas besoin de conserver l'information sur les 0 et les 1 alors on obtient directement la matrice de booléen et on fait la somme en ligne.

Cordialement,
Maxime

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

Re: Fonction ou macro

Messagepar Mickael Canouil » 26 Mar 2019, 10:54

Logez Maxime a écrit :Si tu veux réellement comparer les différentes méthodes alors il ne faut pas inclure dans ton code tout ce qui concerne la création des objets, sinon la différence que tu observes n'est pas représentative des différences.

Seul le temps de calcul total ne sera pas représentatif (et dans le cas présent l'impact de la création est vraiment négligeable).
La mesure relative, reste valide, puisque la création des objets est strictement identique entre les méthodes testés.

Code : Tout sélectionner

Benchmark summary:
Time units : microseconds
         expr n.eval  min lw.qu median mean up.qu   max  total relative
      Bastien    100 7390  7690   7890 8100  8030 11900 810000     20.1
 Bastien_noif    100 7090  7320   7430 7790  7540 11900 779000     19.0
      Mickael    100  396   420    433  482   451  4790  48200      1.1
       Maxime    100  366   384    392  424   410  2870  42400      1.0
Mickaël
mickael.canouil.fr | rlille.fr

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

*

Messagepar Elsa Nario » 04 Avr 2019, 12:42

*


Retourner vers « Questions en cours »

Qui est en ligne

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