web-dev-qa-db-fra.com

écriture dans une trame de données à partir d'une boucle for dans R

J'essaye d'écrire d'une boucle vers une trame de données dans R, par exemple une boucle comme celle-ci>

for (i in 1:20) {
print(c(i+i,i*i,i/1))}

et d'écrire chaque ligne de 3 valeurs dans une trame de données avec trois colonnes, de sorte que chaque itération prenne une nouvelle ligne. J'ai essayé d'utiliser une matrice, avec ncol = 3 et rempli de lignes, mais je ne récupère que le dernier élément de la boucle.

Merci.

16
CCID

Vous pouvez utiliser rbind:

d <- data.frame()
for (i in 1:20) {d <- rbind(d,c(i+i, i*i, i/1))}
23
Karsten W.

Une autre façon serait

do.call("rbind", sapply(1:20, FUN = function(i) c(i+i,i*i,i/1), simplify = FALSE))


     [,1] [,2] [,3]
 [1,]    2    1    1
 [2,]    4    4    2
 [3,]    6    9    3
 [4,]    8   16    4
 [5,]   10   25    5
 [6,]   12   36    6

Si vous ne spécifiez pas simplify = FALSE, vous devez transposer le résultat en utilisant t. Cela peut être fastidieux pour les grandes structures.

Cette solution est particulièrement pratique si vous avez un ensemble de données sur le grand côté et/ou que vous devez le répéter plusieurs fois.

J'offre quelques timings de solutions dans ce "fil".

> system.time(do.call("rbind", sapply(1:20000, FUN = function(i) c(i+i,i*i,i/1), simplify = FALSE)))
   user  system elapsed 
   0.05    0.00    0.05 

> system.time(ldply(1:20000, function(i)c(i+i, i*i, i/1)))
   user  system elapsed 
   0.14    0.00    0.14 

> system.time({d <- matrix(nrow=20000, ncol=3) 
+ for (i in 1:20000) { d[i,] <- c(i+i, i*i, i/1)}})
   user  system elapsed 
   0.10    0.00    0.09 

> system.time(ldply(1:20000, function(i)c(i+i, i*i, i/1)))
   user  system elapsed 
  62.88    0.00   62.99 
10
Roman Luštrik

Si toutes vos valeurs ont le même type et que vous connaissez le nombre de lignes, vous pouvez utiliser une matrice de la manière suivante (ce sera très rapide):

d <- matrix(nrow=20, ncol=3) 
for (i in 1:20) { d[i,] <- c(i+i, i*i, i/1)}

Si vous avez besoin d'une trame de données, vous pouvez utiliser rbind (comme le suggère une autre réponse), ou des fonctions du package plyr comme ceci:

library(plyr)
ldply(1:20, function(i)c(i+i, i*i, i/1))
6
cafe876

Les boucles For ont des effets secondaires, donc la manière habituelle de le faire est de créer une trame de données vide avant la boucle, puis d'y ajouter à chaque itération. Vous pouvez l'instancier à la bonne taille puis affecter vos valeurs à la i 'ème ligne à chaque itération, ou bien l'ajouter et réattribuer le tout en utilisant rbind().

La première approche offrira de meilleures performances pour les grands ensembles de données.

6
Shane