appliquer une fonction à tout les objets

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

yannick ramage
Messages : 22
Enregistré le : 21 Juin 2007, 09:35

appliquer une fonction à tout les objets

Messagepar yannick ramage » 25 Nov 2008, 21:52

Bonjour,

J'aimerai appliquer cette fonction:

Code : Tout sélectionner

library(rpart)
remplacement<-" "

f<-function(x){
if (is.data.frame(x)){
y<-length(x)
for(i in 1:y){
if(is.numeric(x[i])){
box<-boxplot(x[i])
error<-box$out
row_error<-which(x[i]%in%error)
x[i]<-replace(x[i],row_error,remplacement)
as.numeric(x[i])
}}}}

à tous mes objets, naïvement je pensais donc rajouter :

Code : Tout sélectionner

all<-ls()
f(all)

La dernière ligne ne marche pas et n'affiche pas de message d'erreur Par quoi pourrai je la remplacer?

De plus je n'arrive pas à faire en sorte que la boucle for prenne en compte la longueur de la colonne et non la longueur du data frame car

Code : Tout sélectionner

y<-length(x[i])
for(i in 1:y)

c'est un serpent qui se mord la queue...Donc si quelqu'un veut bien éclairer ma lanterne


Pour explication:
Je débute en programmation et je dois préparer un script permettant de générer des courbes à partir d'une base de données. Ces bases sont assez conséquentes mais avec de nombreuses erreurs de saisies. Dans la mesure ou les données sont nombreuses, naturellement homogènes et que les erreurs sont principalement l'ajout ou l'oubli d'un chiffre, je pensais utiliser la fonction précédente.


La solution alternative serai une fonction qui remplace les valeurs de longueur incorrecte mais cela implique de spécifier la longueur de chaque variable et donc de spécifier tous les objets. Cette solution ne nous intéresse pas vraiment car le but est de faire un script qui s'applique à tout sans spécifier les objets.

Tous les conseils sont les bienvenus,merci d'avance,

Yannick Ramage

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

Messagepar Logez Maxime » 25 Nov 2008, 22:49

Bonsoir,

Pour quelqu'un qui débute en progra tu te lances pas dans quelque chose de simple ! J'espère qu'avec la fonction suibvante tu obtiendras ce que tu voudras :

Code : Tout sélectionner

f <- function(x){
  f2 <- function(z){
    if (is.numeric(z)){
      out <- boxplot.stats(z,do.conf=FALSE)$out
      out <- sapply(out,function(e) which(abs(e-z)<1e-7))
      out <- out[!is.na(out)]
      z[out] <- NA
      }
    z
    }
  aux <- x
  x <- get(aux,envir=globalenv())
  if (is.data.frame(x)){
    x[,sapply(x,is.numeric)] <- sapply(x[,sapply(x,is.numeric),drop=FALSE],f2)
    }
  assign(aux,x,envir=globalenv())
  }


un exemple :

Code : Tout sélectionner

X <- data.frame(x=c(rnorm(100),1000),y=sample(letters,101,rep=TRUE))
objects <- ls()
invisible(sapply(objects,f))
tail(X)


Maxime

yannick ramage
Messages : 22
Enregistré le : 21 Juin 2007, 09:35

Messagepar yannick ramage » 25 Nov 2008, 23:02

Merci beaucoup Maxime.

Je vais essayer de faire marcher ça et surtout de le comprendre.

Bonne nuit

Yannick Ramage

yannick ramage
Messages : 22
Enregistré le : 21 Juin 2007, 09:35

Messagepar yannick ramage » 26 Nov 2008, 00:46

Désolé mais cela ne marche pas. j'ai testé en vérolant une table de la base, quand je la rappelle après avoir lancé la fonction, les erreurs ne sont pas corrigées.
Les tables en question sont importé de la base via

Code : Tout sélectionner

 require(RODBC)

puis par

Code : Tout sélectionner

Nom-table<-sqlQuery(Nom_base, "select * from [Nom_table]")


Même résultat avec un tableau créé par un cbind sur vecteurs



Un grand merci quand même




Je ne comprends pas certaines lignes:


Code : Tout sélectionner

 out <- sapply(out,function(e) which(abs(e-z)<1e-7))

quelle est cette fonction (e) et a quoi sert l'expression avec which?

Code : Tout sélectionner

aux <- x
x <- get(aux,envir=globalenv())
assign(aux,x,envir=globalenv())
est ce passage par "aux" via "get" qui permet assign?


Code : Tout sélectionner

x[,sapply(x,is.numeric)] <- sapply(x[,sapply(x,is.numeric),drop=FALSE],f2)

Je ne pas comment la fonction est appliquée à x compte tenue du <- que je comprend pas.


est ce que

Code : Tout sélectionner

x[,sapply(x,is.numeric)]
a la même fonction que if(is.numeric(x){} ?



Désolé si j'en demande trop, la programmation en R m'intéresse et j'essaie de persévérer dans cette voie.

Merci d'avance,

Yannick Ramage

Eric Pagot
Messages : 195
Enregistré le : 15 Fév 2007, 17:10

Messagepar Eric Pagot » 26 Nov 2008, 08:10

J'ai du mal à saisir l'esprit du petit programme. Je vais dire ce que j'ai compris, peut-être sera-t-il possible de progresser...
x est une data.frame
x[i] correspond à une colonne de celle ci
Par exemple prenons x avec 4 colonnes nommées a,b,c,d

Tout d'abord, si l'on veut accéder au contenu de cette colonne il faut nommer celle-ci. x$a donnera un vecteur avec toutes les valeurs de la première colonne, x$b celles de la deuxième, etc...
Donc, pour accéder au contenu de la colonne x[i], il faudra faire la commande : eval(parse(text=paste("x$",names(x[i]),sep=""))) et stocker cette variable (par ex z). Après, il est possible d'éxécuter toutes les manipulations mentionnées.
Ainsi y est l'index du n° de colonne
z sera les valeurs de chaque colonne (il faudra donc plutôt tester celui-ci avec is.numeric(z)).
Vétérinaire CTPA

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

Messagepar Logez Maxime » 26 Nov 2008, 08:30

Bonjour,

Code : Tout sélectionner

out <- sapply(out,function(e) which(abs(e-z)<1e-7))


Sert a savoir quelle valeur de la colonne de ton tableau est égale a une des valeurs out. Je ne me suis pas servi de %in% parce qu'elle fait appel à la fonction match, qui n'est pas adapté a mon avis pour les variables numériques notamment a cause des problèmes de virgules flottantes.

Code : Tout sélectionner

x[,sapply(x,is.numeric)] <- sapply(x[,sapply(x,is.numeric),drop=FALSE],f2)


Ici tu cherches a remplacer uniquement les colonnes de x qui sont numériques.

Code : Tout sélectionner

x[,sapply(x,is.numeric)]

ça permet d'extraire de x que les colonnes qui sont numériques.

Code : Tout sélectionner

aux <- x
x <- get(aux,envir=globalenv())
assign(aux,x,envir=globalenv())

Comme au départ tu voulais faire ça sur tout les objets, alors l'argument de la fonction f n'est pas un objet lui même mais son nom en chaîne de caractère, donc il fallait pouvoir récupérer l'objet a partir de son nom et une fois les modifs de fait "le sauvegarder" avec le même nom.

Donc en fait si ton tableau s'appelle Nom_table (ne pas mettre de "-" dans le nom d'un objet, le "-" faisant référence a une soustraction), alors tu dois utiliser la fonction comme ceci : f("Nom_table").

Voila en espérant que cela est plus clair.

Maxime

yannick ramage
Messages : 22
Enregistré le : 21 Juin 2007, 09:35

Messagepar yannick ramage » 26 Nov 2008, 22:49

Merci pour votre aide

Malheureusement le script de Maxime ne fonctione pas

Code : Tout sélectionner

rm(list=ls())

a<-c(1,2,3,4,5,6,7,8,999)
b<-c(999,2,3,4,5,6,7,8,9)
c<-c(-10,2,3,4,5,6,7,8,9)
 d<-cbind(a,b,c)
 
d
        a   b   c
 [1,]   1 999 -10
 [2,]   2   2   2
 [3,]   3   3   3
 [4,]   4   4   4
 [5,]   5   5   5
 [6,]   6   6   6
 [7,]   7   7   7
 [8,]   8   8   8
 [9,] 999   9   9
 
f <- function(x){
   f2 <- function(z){
     if (is.numeric(z)){
       out <- boxplot.stats(z,do.conf=FALSE)$out
       out <- sapply(out,function(e) which(abs(e-z)<1e-7))
       out <- out[!is.na(out)]
       is.na<-z[out]
       }
     z
     }
  aux <- x
   x <- get(aux,envir=globalenv())
   if (is.data.frame(x)){
     x[,sapply(x,is.numeric)] <- sapply(x[,sapply(x,is.numeric),drop=FALSE],f2)
     }
   assign(aux,x,envir=globalenv())
 
   }   

  objects <- ls()
invisible(sapply(objects,f))

d
        a   b   c
 [1,]   1 999 -10
 [2,]   2   2   2
 [3,]   3   3   3
 [4,]   4   4   4
 [5,]   5   5   5
 [6,]   6   6   6
 [7,]   7   7   7
 [8,]   8   8   8
 [9,] 999   9   9




De même lorsque j'essaie d'intégrer les conseil d'Eric

Code : Tout sélectionner

f <- function(x){
  f2 <- function(z){
    if (is.numeric(z)){
      out <- boxplot.stats(z,do.conf=FALSE)$out
      out <- sapply(out,function(e) which(abs(e-z)<1e-7))
      out <- out[!is.na(out)]
      is.na<-z[out]
      }
    z
    }
  aux <- x
  x <- get(aux,envir=globalenv())
  if (is.data.frame(x)){
    x[,sapply(x,is.numeric)] <- sapply(x[,sapply(x,is.numeric),drop=FALSE],f2)
    }
  assign(aux,x,envir=globalenv())

  }



J'ai compris à quoi sert la ligne

Code : Tout sélectionner

out <- sapply(out,function(e) which(abs(e-z)<1e-7))

mais je ne comprends pas comment elle fonctionne: quelle est cette fonction e et comment e devient il une variable pour le which?


Dans tout les cas, merci beaucoup j'apprends beaucoup grâce à ce post

Bonne nuit

Yannick

Eric Pagot
Messages : 195
Enregistré le : 15 Fév 2007, 17:10

Messagepar Eric Pagot » 27 Nov 2008, 07:53

Serait-il possible de me dire à quoi peut ressembler d après le passage par la fonction f ?
A quoi servent les stats de boxplot ?
Ainsi je saurais un peu mieux répondre.
Vétérinaire CTPA

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

Messagepar Logez Maxime » 27 Nov 2008, 08:21

Re,

il est normal que la fonction f ne fonctionne pas sur l'objet d puisque l'objet d est ........... une matrice ! Faire attention avant de dire que le code que les gens te donnent ne fonctionne pas, alors qu'en fait c'est toi qui ne l'utilise pas correctement.

Code : Tout sélectionner

class(d)
[1] "matrix"


Mais si tu la transformes en data frame :

Code : Tout sélectionner

d <- as.data.frame(d)
objects <- ls()

f <- function(x){
  f2 <- function(z){
    if (is.numeric(z)){
      out <- boxplot.stats(z,do.conf=FALSE)$out
      out <- sapply(out,function(e) which(abs(e-z)<1e-7))
      out <- out[!is.na(out)]
      z[out] <- NA
      }
    z
    }
  aux <- x
  x <- get(aux,envir=globalenv())
  if (is.data.frame(x)){
    x[,sapply(x,is.numeric)] <- sapply(x[,sapply(x,is.numeric),drop=FALSE],f2)
    }
  assign(aux,x,envir=globalenv())
  }

invisible(sapply(objects,f))

d
   a  b  c
1  1 NA NA
2  2  2  2
3  3  3  3
4  4  4  4
5  5  5  5
6  6  6  6
7  7  7  7
8  8  8  8
9 NA  9  9


Voila une fonction qui fonctionne aussi bien avec les data.frame que les matrices :

Code : Tout sélectionner

a<-c(1,2,3,4,5,6,7,8,999)
b<-c(999,2,3,4,5,6,7,8,9)
c<-c(-10,2,3,4,5,6,7,8,9)
d<-cbind(a,b,c)
d2 <- as.data.frame(d)
object <- ls()

f <- function(x){
  f2 <- function(z){
    if (is.numeric(z)){
      out <- boxplot.stats(z,do.conf=FALSE)$out
      out <- sapply(out,function(e) which(abs(e-z)<1e-7))
      out <- out[!is.na(out)]
      z[out] <- NA
      }
    z
    }
  aux <- x
  x <- get(aux,envir=globalenv())
  if (inherits(x,c("data.frame","matrix"))){
    nums <- apply(x,2,is.numeric)
    x[,nums] <- apply(x[,nums,drop=FALSE],2,f2)
    }
  assign(aux,x,envir=globalenv())
  }
 
invisible(sapply(object,f))

d
       a  b  c
 [1,]  1 NA NA
 [2,]  2  2  2
 [3,]  3  3  3
 [4,]  4  4  4
 [5,]  5  5  5
 [6,]  6  6  6
 [7,]  7  7  7
 [8,]  8  8  8
 [9,] NA  9  9

d2
   a  b  c
1  1 NA NA
2  2  2  2
3  3  3  3
4  4  4  4
5  5  5  5
6  6  6  6
7  7  7  7
8  8  8  8
9 NA  9  9


Pour ce qui est de :

Code : Tout sélectionner

out <- sapply(out,function(e) which(abs(e-z)<1e-7))

function(e) est juste une fonction comme les autres que je définie comme étant which(abs(e-z)<1e-7)), j'aurai pu aussi faire :

Code : Tout sélectionner

bob <- function(x) which(abs(x-z)<1e-7)
sapply(out,bob)

Ici ce que tu passes dans la fonction c'est toutes les valeurs out, et avec le which tu vas chercher a savoir quelle est la valeur de z pour laquelle la différence entre la valeur de out et les valeurs de z sont égales à 0 (en fait ici inférieures à 1e-7). Le problème des out des boxplot, c'est qu'il te donne les valeurs des outilers, mais ce qu'on a besoin ce n'est pas de la valeur en elle même mais de sa place dans les colonnes. C'est que cherche à savoir le code sapply(out,function(e) which(abs(e-z)<1e-7)). Une fois que tu connais la localisation de ces valeurs dans les colonnes alors tu peux remplacer ces valeurs par des NA.

Maxime

yannick ramage
Messages : 22
Enregistré le : 21 Juin 2007, 09:35

Messagepar yannick ramage » 27 Nov 2008, 20:23

Merci!

Effectivement je me suis mal exprimé, au lieu de "Malheureusement le script de Maxime ne fonctionne pas ", j'aurai du dire ""Malheureusement je ne sais pas faire fonctionner le script de Maxime". J'en prends note

Merci pour ton aide et tes explications

Yannick

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

Messagepar Logez Maxime » 27 Nov 2008, 21:50

Re,

ça n'avait irne der pseonl, ni rien avoir avec moi. Je voulais juste te mettre en garde dans le premier post on peut voir ceci :
f<-function(x){
if (is.data.frame(x)){
y<-length(x)
for(i in 1:y){
if(is.numeric(x[i])){
box<-boxplot(x[i])
error<-box$out
row_error<-which(x[i]%in%error)
x[i]<-replace(x[i],row_error,remplacement)
as.numeric(x[i])
}}}}

Qui voulait dire que tu voulais appliquer ta fonction a des data frames et ensuite tu essayais d'appliquer la fonction f sur une matrice issu d'un cbind. Il faut donc bien voir ce que tu cherches à faire et bien voir que les différents types d'objets ont leur spécificités. C'est quelque chose d'important en proga. Avant de crier au loup faire attention que ça ne soit pas toi qui te méprend. Ce qui veut pas dire que les gens ne se trompent pas, mais il vaut mieux être sur que l'on est raison avant de savoir si ce sont les autres qui ont tort.

Sur ce bonne nuit.

Maxime

yannick ramage
Messages : 22
Enregistré le : 21 Juin 2007, 09:35

Messagepar yannick ramage » 27 Nov 2008, 22:11

J'ai bien compris et merci pour ces conseils

A la prochaine,

Yannick


Retourner vers « Questions en cours »

Qui est en ligne

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