R Iterate dataset generation

Viewed 48

I want to generate 21 random normal distribution data.frames with two variables (using mvrnorm), based on 21 parameters that are stored in [1:21] num/chr strings. Plus, each data.frame should contain two columns with strings that are identical for each of the 21 sets (That'll make sense once I rbind them together)

Let's say AGQ.mu2.mat stores means for the first variable (stddev = 1), Std.mu2.mat for the second (stddev = 20), and ORIG and ID store the two strings (I replaced the data with some LotR names), and let corr be = .30 and n always 300:

r<-0.30
ORIG<-c("Ang","Ang","Ang","DGu","DGu","DGu", "Har", 
        "Har", "Har", "Isg", "Isg", "Isg", "Mor", "Mor", 
        "Mor", "MMo", "MMo", "MMo", "Rhu", "Rhu", "Rhu")
ID<-c("a","b","c","a","b","c","a","b","c",
         "a","b","c","a","b","c","a","b","c","a","b","c")
AGQ.mu2.mat <- c(-1.06, -1.27, -1.97, -3.27, -3.32, -2.32, -1.05, -0.36, -1.85, -2.30, -2.49, -2.90, -0.80, -0.62, -0.56,  1.22,  1.62,  0.44, -1.43, -1.08, -2.34)
Std.mu2.mat <- c(107, 100, 102, 124, 118, 120, 147, 152, 141, 154, 160, 155, 125, 123, 116, 103, 106, 107, 123, 126, 117)

I want to iterate

dt<-data.frame(mvrnorm(n=300, mu=c(AGQ.mu2.mat[1],Std.mu2.mat[1]),
                       Sigma=matrix(c(1, r*20, r*20, (20^2)),
                                  nrow=2), empirical=TRUE))
dt<-rename(dt, "AGQ" = "X1","Std" = "X2")
dt$Herkunft<-ORIG[1]
dt$Bat_ID<-ID[1]

over all 21 entries of the parameter vectors, resulting in 21 uniquely named data frames.

I've tried

for (i in 1:21)
  {
dt<-data.frame(mvrnorm(n=300, mu=c(AGQ.mu2.mat[i],Std.mu2.mat[i]),
                       Sigma=matrix(c(1, r*20, r*20, (20^2)),
                                  nrow=2), empirical=TRUE))
dt<-rename(dt, "AGQ" = "X1","Std" = "X2")
dt$Herkunft<-ORIG[i]
dt$Bat_ID<-ID[i]
}

and

dt<-data.frame(mvrnorm(n=300, mu=c(rep(AGQ.mu2.mat,each=1),rep(Std.mu2.mat, each=1)),
                       Sigma=matrix(c(1, r*20, r*20, (20^2)),
                                    nrow=2), empirical=TRUE))
dt<-rename(dt, "Aggr" = "X1","Std" = "X2")
dt$Herkunft<-rep(ORIG,each=1)
dt$Bat_ID<-rep(ID,each=1)

to no avail; and even then, this would generate the same dataset over and over without creating uniquely named new ones.

I'd really appreciate any help or approaches on how to iterate this. Thanks in advance!

2 Answers

you need to use some way to gather the results. I choose to use list which is appended. Other solution might be to use rbind. You have to shape your matrix with nrow/ncol arguments.

library(MASS)

r<-0.30
ORIG<-c("Ang","Ang","Ang","DGu","DGu","DGu", "Har", 
        "Har", "Har", "Isg", "Isg", "Isg", "Mor", "Mor", 
        "Mor", "MMo", "MMo", "MMo", "Rhu", "Rhu", "Rhu")
ID<-c("a","b","c","a","b","c","a","b","c",
         "a","b","c","a","b","c","a","b","c","a","b","c")

AGQ.mu2.mat <- 1:21
Std.mu2.mat <- 1:21

results <- list()

for (i in 1:21) {
dt<-data.frame(mvrnorm(n=300, mu=c(AGQ.mu2.mat[i],Std.mu2.mat[i]),
                       Sigma=matrix(c(1, r*20, r*20, (20^2)), nrow = 2), empirical=TRUE))
colnames(dt) <- c("AGQ","Std")
dt$Herkunft<-ORIG[i]
dt$Bat_ID<-ID[i]

results[[i]] <- dt
}

join all results

do.call(rbind, results)

validation:

> cor(results[[1]][,1:2]);apply(results[[1]][,1:2], 2, mean);apply(results[[1]][,1:2], 2, sd)
    AGQ Std
AGQ 1.0 0.3
Std 0.3 1.0
AGQ Std 
  1   1 
AGQ Std 
  1  20 

This solution using dplyr and purrr may help...

library(MASS)
library(dplyr)
library(purrr)

r <-0.30

ORIG<-c("Ang","Ang","Ang","DGu","DGu","DGu", "Har", 
        "Har", "Har", "Isg", "Isg", "Isg", "Mor", "Mor", 
        "Mor", "MMo", "MMo", "MMo", "Rhu", "Rhu", "Rhu")

ID<-c("a","b","c","a","b","c","a","b","c",
      "a","b","c","a","b","c","a","b","c","a","b","c")

AGQ.mu2.mat <- c(-1.06, -1.27, -1.97, -3.27, -3.32, -2.32, -1.05, -0.36, -1.85, -2.30, -2.49, -2.90, -0.80, -0.62, -0.56,  1.22,  1.62,  0.44, -1.43, -1.08, -2.34)
Std.mu2.mat <- c(107, 100, 102, 124, 118, 120, 147, 152, 141, 154, 160, 155, 125, 123, 116, 103, 106, 107, 123, 126, 117)

listofdf <- purrr::map2(AGQ.mu2.mat, 
            Std.mu2.mat,
            ~ data.frame(MASS::mvrnorm(n = 300, 
                                       mu=c(.x, .y),
                                       Sigma = matrix(c(1, r*20, r*20, (20^2)), nrow=2), 
                                       empirical=TRUE))
) %>% 
   purrr::map2(ORIG, ~ mutate(.x, Herkunft = .y)) %>%
   purrr::map2(ID, ~ mutate(.x, Bat_ID = .y))

head(listofdf[[4]])
#>          X1         X2 Herkunft Bat_ID
#> 1 0.4329040  17.616240      DGu      a
#> 2 2.6589457  -9.385099      DGu      a
#> 3 2.3626722   9.815020      DGu      a
#> 4 1.8998816 -24.551505      DGu      a
#> 5 0.2506713   0.792565      DGu      a
#> 6 3.4961960   8.112878      DGu      a


### since you mentioned binding them all together
onebigdf <- bind_rows(listofdf)
Related