web-dev-qa-db-fra.com

Pourquoi les objets R ne s'impriment-ils pas dans une fonction ou une boucle "for"?

J'ai une matrice R nommée ddd. Quand j'entre, tout fonctionne bien:

i <- 1
shapiro.test(ddd[,y])
ad.test(ddd[,y]) 
stem(ddd[,y]) 
print(y) 

Les appels à Shapiro Wilk, Anderson Darling, et à la tige fonctionnent tous, et extraient la même colonne.

Si je mets ce code dans une boucle "for", les appels à Shapiro Wilk et Anderson Darling cessent de fonctionner, tandis que l'appel stem & leaf et l'appel print continuent de fonctionner.

for (y in 7:10) {
    shapiro.test(ddd[,y])
    ad.test(ddd[,y]) 
    stem(ddd[,y]) 
    print(y)
}

The decimal point is 1 digit(s) to the right of the |

  0 | 0
  0 | 899999
  1 | 0

[1] 7

La même chose se produit si j'essaie d'écrire une fonction. SW & AD ne fonctionnent pas. Les autres appels le font.

> D <- function (y) {
+ shapiro.test(ddd[,y])
+ ad.test(ddd[,y]) 
+ stem(ddd[,y]) 
+ print(y)  }

> D(9)

  The decimal point is at the |

   9 | 000
   9 | 
  10 | 00000

[1] 9

Pourquoi tous les appels ne se comportent-ils pas de la même manière?

53
Sal Leggio

En boucle, l'impression automatique est désactivée, car elle se trouve à l'intérieur d'une fonction. Vous devez explicitement print quelque chose dans les deux cas si vous voulez voir la sortie. Le [1] 9 ce que vous obtenez est dû au fait que vous imprimez explicitement les valeurs de y.

Voici un exemple de la façon dont vous pourriez envisager de procéder.

> DF <- data.frame(A = rnorm(100), B = rlnorm(100))
> y <- 1
> shapiro.test(DF[,y])

    Shapiro-Wilk normality test

data:  DF[, y] 
W = 0.9891, p-value = 0.5895

Nous avons donc l'impression automatique. Dans la boucle, nous devrions faire ceci:

for(y in 1:2) {
    print(shapiro.test(DF[,y]))
}

Si vous souhaitez imprimer plus de tests, ajoutez-les simplement en tant que lignes supplémentaires dans la boucle:

for(y in 1:2) {
    writeLines(paste("Shapiro Wilks Test for column", y))
    print(shapiro.test(DF[,y]))
    writeLines(paste("Anderson Darling Test for column", y))
    print(ad.test(DF[,y]))
}

Mais ce n'est pas très attrayant, sauf si vous aimez lire à travers des rames de sortie. Au lieu de cela, pourquoi ne pas enregistrer les objets de test ajustés et ensuite vous pouvez les imprimer et les étudier, peut-être même les traiter pour agréger les statistiques de test et les valeurs p dans un tableau? Vous pouvez le faire en utilisant une boucle:

## object of save fitted objects in
obj <- vector(mode = "list", length = 2)
## loop
for(y in seq_along(obj)) {
    obj[[y]] <- shapiro.test(DF[,y])
}

On peut alors regarder les modèles en utilisant

> obj[[1]]

    Shapiro-Wilk normality test

data:  DF[, y] 
W = 0.9891, p-value = 0.5895

par exemple, ou en utilisant lapply, qui s'occupe de configurer l'objet que nous utilisons pour stocker les résultats pour nous:

> obj2 <- lapply(DF, shapiro.test)
> obj2[[1]]

    Shapiro-Wilk normality test

data:  X[[1L]] 
W = 0.9891, p-value = 0.5895

Disons maintenant que je voulais extraire les W et p-value données, nous pouvons traiter l'objet en stockant tous les résultats pour extraire les bits que nous voulons, par exemple:

> tab <- t(sapply(obj2, function(x) c(x$statistic, x$p.value)))
> colnames(tab) <- c("W", "p.value")
> tab
          W      p.value
A 0.9890621 5.894563e-01
B 0.4589731 1.754559e-17

Ou pour ceux qui ont un penchant pour les étoiles d'importance:

> tab2 <- lapply(obj2, function(x) c(W = unname(x$statistic), 
+                                    `p.value` = x$p.value))
> tab2 <- data.frame(do.call(rbind, tab2))
> printCoefmat(tab2, has.Pvalue = TRUE)
       W p.value    
A 0.9891  0.5895    
B 0.4590  <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Cela doit être meilleur que le tir de sortie vers l'écran que vous devez ensuite traverser?

56
Gavin Simpson

Pas une nouvelle réponse, mais en plus de ce qui précède: "flush.console ()" est nécessaire pour forcer l'impression à avoir lieu PENDANT la boucle plutôt qu'après. La seule raison pour laquelle j'utilise print () pendant une boucle est de montrer la progression, par exemple, de la lecture de nombreux fichiers.

for (i in 1:10) {
  print(i)
  flush.console()
  for(j in 1:100000)
    k <- 0
}
37
J. Win.

Fantastique réponse de Gavin Simpson. J'ai pris le dernier morceau de magie et l'ai transformé en fonction.

sw.df <- function ( data ) { 
   obj <- lapply(data, shapiro.test)
   tab <- lapply(obj, function(x) c(W = unname(x$statistic), `p.value` = x$p.value))
   tab <- data.frame(do.call(rbind, tab))
   printCoefmat(tab, has.Pvalue = TRUE)
}

Ensuite, vous pouvez simplement l'appeler avec votre trame de données sw.df (df)

Et si vous voulez essayer une transformation: sw.df (log (df))

5
Rolando