Remplir une trame de données dans R dans une boucle

J'essaie de remplir une trame de données à partir d'une boucle for Dans R. les noms des colonnes sont générés dynamiquement dans la boucle et la valeur de certaines des variables de boucle est utilisée comme valeurs lors du remplissage de la trame de données. Par exemple, le nom de la colonne actuelle peut être un nom de variable en tant que chaîne dans la boucle, et la colonne peut prendre la valeur de l'itérateur actuel comme valeur dans le cadre de données.

J'ai essayé de créer un cadre de données vide en dehors de la boucle, comme ça

d = data.frame()

Mais je ne peux vraiment rien faire avec, au moment où j'essaie de le remplir, je rencontre une erreur

 d[1] = c(1,2)
Error in `[<-.data.frame`(`*tmp*`, 1, value = c(1, 2)) : 
  replacement has 2 rows, data has 0

Ce qui peut être un bon moyen de réaliser ce que je cherche à faire. S'il vous plaît laissez-moi savoir si je n'étais pas clair.

22
demandé sur Brian Tompsett - 汤莱恩 2012-11-18 21:13:57

3 réponses

Vous pouvez le faire comme ceci:

 iterations = 10
 variables = 2

 output <- matrix(ncol=variables, nrow=iterations)

 for(i in 1:iterations){
  output[i,] <- runif(2)

 }

 output

, puis de le transformer en un data.frame

 output <- data.frame(output)
 class(output)

Ce Que cela fait:

  1. créer une matrice avec des lignes et des colonnes en fonction de la croissance attendue
  2. insérer 2 nombres aléatoires dans la matrice
  3. convertir cela en un dataframe après la boucle est terminée.
31
répondu Seb 2012-11-18 17:30:57

Il est souvent préférable d'éviter les boucles et d'utiliser des fonctions vectorisées. Si cela n'est pas possible, il y a deux approches:

  1. Préallouer votre data.frame. Ceci n'est pas recommandé car l'indexation est lente pour data.frames.
  2. utilisez une autre structure de données dans la boucle et transformez-la en data.frame par la suite. Un list est très utile ici.

Exemple pour illustrer l'approche générale:

mylist <- list() #create an empty list

for (i in 1:5) {
  vec <- numeric(5) #preallocate a numeric vector
  for (j in 1:5) { #fill the vector
    vec[j] <- i^j 
  }
  mylist[[i]] <- vec #put all vectors in the list
}
df <- do.call("rbind",mylist) #combine all vectors into a matrix

Dans cet exemple, il n'est pas nécessaire d'utiliser un list, vous pouvez préallouer un matrix. Cependant, si vous ne savez pas combien d'itérations votre boucle aura besoin, vous devez utiliser un list.

Enfin, voici une alternative vectorisée à la boucle d'exemple:

outer(1:5,1:5,function(i,j) i^j)

Comme vous le voyez, c'est plus simple et aussi plus efficace.

37
répondu Roland 2012-11-18 17:51:27

J'ai eu un cas où j'avais besoin d'utiliser une trame de données dans une fonction de boucle for. dans ce cas, c'était le "efficace", Cependant, gardez à l'esprit que la base de données était petite et que les itérations dans la boucle étaient très simples. Mais peut-être que le code pourrait être utile pour quelqu'un avec des conditions similaires.

Le For loop avait pour but d'utiliser la fonction raster extract le long de cinq emplacements (c'est-à-dire 5 Tokio, New York, SAU Paulo, Seul & Mexico city) et chaque emplacement avaient leurs grilles raster respectives. J'avais une base de données de points spatiaux avec plus de 1000 observations allouées dans les 5 emplacements différents et j'avais besoin d'extraire des informations de 10 grilles raster différentes (deux grilles par emplacement). En outre, pour l'analyse ultérieure, j'avais non seulement besoin des valeurs raster mais aussi de l'ID unique pour chaque observation.

Après avoir préparé les données spatiales, qui comprenaient les tâches suivantes:

  1. importer des points shapefile avec le readOGR Fonction (paquet rgdap)
  2. importer des fichiers raster avec la fonction raster (package raster)
  3. empiler les grilles du même emplacement dans un fichier, avec la fonction empiler (paquet raster)

Ici le pour la boucle le code avec l'utilisation de bloc de données:

1. Ajouter des rasters empilés par emplacement dans une liste

raslist <- list(LOC1,LOC2,LOC3,LOC4,LOC5)

2. Créer un dataframe vide, ce sera la sortie fichier

TB <- data.frame(VAR1=double(),VAR2=double(),ID=character())

3. Configuration de la fonction boucle

L1 <- seq(1,5,1) # the location ID is a numeric variable with values from 1 to 5 

for (i in 1:length(L1)) {
  dat=subset(points,LOCATION==i) # select corresponding points for location [i] 
  t=data.frame(extract(raslist[[i]],dat),dat$ID) # run extract function with points & raster stack for location [i]
  names(t)=c("VAR1","VAR2","ID") 
  TB=rbind(TB,t)
}
0
répondu scs76 2017-08-24 17:08:27