Problème user function appliquée à un data frame

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

Colin Ginot
Messages : 11
Enregistré le : 19 Nov 2018, 14:08

Problème user function appliquée à un data frame

Messagepar Colin Ginot » 20 Nov 2018, 09:36

Bonjour,

Mon but est d'appliquer la fonction décrite ci dessous à l'ensemble des données (réelle, comprise entre 0 et 20) d'un data frame dimension 100000*15.

Code : Tout sélectionner

hab_p_bba1 <- function(x){
  xi_p = c(0,0.1,0.3,0.6,1.2,20) #abscisses des différentes profondeur (penser à ajouter l'abscisse 0)
  yi_p = c(0,1,0.950617284,0.3950617284,0,0) # Ordonnées unitaire de la densité de pop (mm rq)
 
  for (i in 1:length(xi_p)){
    if (x >= xi_p[i] && x < xi_p[i+1]){
      result <- (((yi_p[i+1]-yi_p[i])/(xi_p[i+1]-xi_p[i]))*(x-xi_p[i])+yi_p[i])
    }
  }
  return(result)
}


Cependant, si j'applique cette fonction directement à un data frame ( hab_p_bba1(df)) j’obtiens des valeurs erronées.

J'ai déjà fait quelques recherches, sans succès :

J'ai essayé de l'appliquer à un vecteur de la même manière j'obtiens courbe linéaire de la même pente que la fonction en la première valeur du vecteur.
Sinon, avec une boucle for ou un lapply, j'ai de bons résultats mais malheureusement pas transférable au dataframe (trop long pour la boucle et valeurs bizarres quand reconversion en df pour lapply).
Un exemple vaut mieux que des explications :

Code : Tout sélectionner

x <- seq(0,3,0.05)

y <- c()
for (i in x){
  print(i)
  y <- append(y,hab_p_bba1(i))
}
plot(x,y)

z <- hab_p_bba1(x)
plot(x,z)

lap <- lapply(X = x, FUN = hab_p_bba1)
plot(x,lap)


PS : ça ne vient pas de la boucle for dans la fonction car j'ai essayé de l'écrire sans boucle, j'ai les mêmes problèmes.

Je ne connais pas bien R (et l'info en général). Mais comme on ne spécifie pas le type de la variable d'entrée et de sortie de la fonction, je me dis qu'il pense peut être que je lui rentre un réel et n’essaie pas d'appliquer la fonction indépendamment à chacune des données.

Quelqu'un aurait une solution à mon problème ?

Merci !

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: Problème user function appliquée à un data frame

Messagepar Pierre-Yves Berrard » 20 Nov 2018, 12:37

Bonjour,

Colin Ginot a écrit :Cependant, si j'applique cette fonction directement à un data frame ( hab_p_bba1(df)) j’obtiens des valeurs erronées.

(sous réserve d'avoir bien compris le problème)
Comme votre fonction prend en entrée un vecteur, pour l'appliquer à toutes les colonnes (qui sont des vecteurs) d'un data.frame, c'est là qu'il faut utiliser lapply :

Code : Tout sélectionner

lapply(df, hab_p_bba1)
PY

Colin Ginot
Messages : 11
Enregistré le : 19 Nov 2018, 14:08

Re: Problème user function appliquée à un data frame

Messagepar Colin Ginot » 20 Nov 2018, 13:21

Comme votre fonction prend en entrée un vecteur


Désolé, je pense ne pas avoir été assez clair. Ma fonction prend en entrée un réel (compris entre 0 et 20). J'ai fait un travail sur les vecteur pour essayer de comprendre le problème.
Mais en effet, j'arrive a appliquer ma fonction sur des vecteurs. Cependant, lapply appliqué au data frame ne fonctionne pas (j'ai des messages d'erreurs, je pense dus au fait que lapply voit les variables du data frame comme des données.

J'ai oublié de précisé que j'avais aussi définit une fonction "plus_1" (qui renvoyait simplement "x+1") et quand je fait "plus_1(df)", j'obtiens bien un data frame avec toute les valeurs incrémentées de 1.
Je ne comprend donc pas pourquoi ça ne fonctionne pas de la même manière pour ma fonction..

Colin.

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: Problème user function appliquée à un data frame

Messagepar Pierre-Yves Berrard » 20 Nov 2018, 13:49

Pardon j'avais lu un peu vite.

En regardant la fonction de plus près, je vois quelque chose de suspect, par exemple avec xi_p[i+1].
Quand i vaut 6, la fonction recherche un 7e élément qui n'existe pas et fait planter la condition if.
PY

Colin Ginot
Messages : 11
Enregistré le : 19 Nov 2018, 14:08

Re: Problème user function appliquée à un data frame

Messagepar Colin Ginot » 20 Nov 2018, 14:39

En effet, je n'avais pas fait attention à ça mais tous mes tests étaient avec des valeurs inférieure à 20 donc R ne m'a pas renvoyé d'erreurs.
La fonction corrigée me donne toujours le même problème cependant.

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: Problème user function appliquée à un data frame

Messagepar Pierre-Yves Berrard » 20 Nov 2018, 15:52

Le problème est ici :

Code : Tout sélectionner

if (x >= xi_p[i] && x < xi_p[i+1])

Quand x ne contient qu'une seule valeur, tout va bien.

Quand x contient plusieurs valeurs (par exemple quand il s'agit d'un data.frame)
"if" attend une seule valeur TRUE/FALSE. Or les comparaisons renvoient autant de TRUE/FALSE que de valeurs de x.
R choisit donc pour tout i le premier TRUE/FALSE et jamais les autres.

Le && ("et logique" avec court-circuit) ne fait que cacher le problème. Remplacer && par & pour s'en convaincre.
PY

Colin Ginot
Messages : 11
Enregistré le : 19 Nov 2018, 14:08

Re: Problème user function appliquée à un data frame

Messagepar Colin Ginot » 20 Nov 2018, 16:42

Merci pour votre réponse !

J'imaginais bien que le problème se trouvait au niveau du if mais j'avoue que je ne sais pas comment R interprète les vecteur dans les fonctions.
Je n'ai pas fait attention a mes "&&", je ne l'utilise que rarement et n'ai pas regardé la subtilité.

Avez vous une piste pour forcer R a faire passer les données de mon data frame indépendamment les unes des autres.
Sans passer par une boucle for puisque physiquement, je n'ai pas besoin d'itération précédente pour faire le calcul donc ça serait une perte de temps (sur 1 000 000 valeurs ça commence à faire). R a juste besoin d'avoir le data frame en mémoire et d'appliquer a fonction à toutes les données.

Je pensais que la famille des apply servait justement à ça. Mais je ne connais pas l'équivalent de "apply" sur chaque données.

Merci encore !

Colin.

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: Problème user function appliquée à un data frame

Messagepar Pierre-Yves Berrard » 20 Nov 2018, 17:56

Colin Ginot a écrit :Je pensais que la famille des apply servait justement à ça. Mais je ne connais pas l'équivalent de "apply" sur chaque données.

lapply ou sa variante avec simplification finale sapply
PY

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: Problème user function appliquée à un data frame

Messagepar Pierre-Yves Berrard » 20 Nov 2018, 18:28

Une solution en utilisant findInterval, qui est vectorielle :

Code : Tout sélectionner

hab_p_bba1 <- function(x) {
 
  xi_p <- c(0,0.1,0.3,0.6,1.2,20) #abscisses des différentes profondeur (penser à ajouter l'abscisse 0)
  yi_p <- c(0,1,0.950617284,0.3950617284,0,0) # Ordonnées unitaire de la densité de pop (mm rq)
 
  i <- findInterval(x, xi_p)
  (yi_p[i+1] - yi_p[i]) / (xi_p[i+1] - xi_p[i]) * (x - xi_p[i]) + yi_p[i]

}

x <- seq(0, 3, by = 0.05)
y <- hab_p_bba1(x)
plot(x, y)

Devrait pouvoir s'appliquer sur un data.frame ou une matrice.
PY

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

Re: Problème user function appliquée à un data frame

Messagepar Logez Maxime » 21 Nov 2018, 07:49

Bonjour,

tu peux aller encore plus loin dans la vectorisation si tu ne répètes pas à chaque fois les mêmes calculs :

Code : Tout sélectionner

hab_p_bba1.2<- function(x) {
  xi_p = c(0,0.1,0.3,0.6,1.2,20) #abscisses des différentes profondeur (penser à ajouter l'abscisse 0)
  yi_p = c(0,1,0.950617284,0.3950617284,0,0) # Ordonnées unitaire de la densité de pop (mm rq)
 
  dx <- diff(xi_p)
  dy <- diff(yi_p)
  qd <- dy/dx
 
  i <- findInterval(x, xi_p)
  res <- qd[i]*(x-xi_p[i])+yi_p[i]
  res
}
Après tu peux appliquer cette fonction au colonne de ton tableau abec un lapply ou sapply ou vapply ou une boucle.

Cordialement,
Maxime

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: Problème user function appliquée à un data frame

Messagepar Pierre-Yves Berrard » 21 Nov 2018, 08:36

Ou carrément les sortir de la fonction si ces valeurs sont constantes :

Code : Tout sélectionner

xi_p <- c(0,0.1,0.3,0.6,1.2,20) #abscisses des différentes profondeur (penser à ajouter l'abscisse 0)
yi_p <- c(0,1,0.950617284,0.3950617284,0,0) # Ordonnées unitaire de la densité de pop (mm rq)
 
dx <- diff(xi_p)
dy <- diff(yi_p)
qd <- dy/dx

hab_p_bba1.3<- function(x) {
  i <- findInterval(x, xi_p)
  qd[i] * (x - xi_p[i]) + yi_p[i]
}
PY

Colin Ginot
Messages : 11
Enregistré le : 19 Nov 2018, 14:08

Re: Problème user function appliquée à un data frame

Messagepar Colin Ginot » 21 Nov 2018, 08:44

Merci beaucoup, ça marche parfaitement !
Je vais regarder un peu comment marche le vectorisation pour éviter ce problème à l'avenir.

Ou carrément les sortir de la fonction si ces valeurs sont constantes :

En fait mon but est d'avoir plusieurs fonctions de ce type avec chacune des valeurs xi et yi différentes. C'est pour ça que je passe par des fonctions, pour pouvoir les appeler indépendamment dans d'autres scripts.

Merci encore.

Colin.

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

Re: Problème user function appliquée à un data frame

Messagepar Logez Maxime » 21 Nov 2018, 08:48

re,

personnellement je n'aime pas trop la solution qui consiste à stocker dans l'environnement global tout un tas d'objets qui ne servent qu'en interne d'une fonction. Si ces objets servent par ailleurs alors c'est différent. Une solution hybride est de placer ces objets en argument de la fonction avec des valeurs par défaut qui pourront être modifiées au besoin.

Code : Tout sélectionner

hab_p_bba1.4 <- function(x, xi_p = c(0,0.1,0.3,0.6,1.2,20),
  yi_p = c(0,1,0.950617284,0.3950617284,0,0)) {

  dx <- diff(xi_p)
  dy <- diff(yi_p)
  qd <- dy/dx

  u <- findInterval(x, xi_p)
  res <- qd[u]*(x-xi_p[u])-yi_p[u]
  res
}

[Edit]Avec cette fonction tu peux modifier les valeurs de xi_p et de yi_p selon tes colonnes ou ce que tu cherches à faire.
Si tu ne veux pas mettre de valeur par défaut il te faut écrire function(x, xi_p, yi_p) à la place de function(x, xi_p = c(...), yi_p = c(...))
Cordialement,
Maxime

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: Problème user function appliquée à un data frame

Messagepar Pierre-Yves Berrard » 21 Nov 2018, 08:49

D'accord avec toi, Maxime, mais comme la fonction va être appelée un certain nombre de fois, je me devais d'évoquer cette possibilité !

Par ailleurs, sortir ces valeurs de la fonction ne veut pas forcément dire polluer l'environnement global. On peut être à l'intérieur d'une autre fonction (qui traiterait un data.frame en entier par exemple).
PY

Colin Ginot
Messages : 11
Enregistré le : 19 Nov 2018, 14:08

Re: Problème user function appliquée à un data frame

Messagepar Colin Ginot » 21 Nov 2018, 08:54

Oui de même, on m'a habituer à coder le moins possible des variables dans l'environnement global.
Pour ce qui est de mettre les valeurs en arguments, j'y avait pensé mais je préfère coder plusieurs fonctions pour la compréhension de mes scripts.

Pierre-Yves, bien que la fonction est appelée 100 000 fois, ce n'est pas très gênant car le lapply permet de le faire en parallèle (enfin c'est ce que j'en ai compris), ce qui rend mon calcul presque instantané.


Retourner vers « Questions en cours »

Qui est en ligne

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