1

I'm having difficulty populating a matrix within an lapply loop.

In my data, I have a list of 135 geospatial points. Within the lapply loop, I am calculating various metrics based on the landscape within 3 different radii from these site coordinates. What I would like to do is cycle through each combination of 135 sites and 3 radii, then populate each row of my blank, pre-prepared matrix with the (site,radius,metric1,metric2,metric3).

I have created a simple script that replicates the issue I'm running into. If it is possible for me to apply the do.call(rbind, absdf) command as in here then I have not yet figured out how...

# Generate empty matrix:
mymatrix <- matrix(,nrow=18, ncol=5)

# A vector with length of x (in my data this is the list of 135 sites):
a <- 1:6
#These sets will represent my metrics 
b <- rnorm(6, 5, 10)
c <- rnorm(6, 100, 20)
d <- rnorm(6, 20, 20)

# Radius vector:
rad <- c(100,200,300)

# The loop: lapply for site within lapply for radius
lapply(1:3,function(r){
  lapply(1:6,function(x){
  row.number <- (r-1)*6+x 
  tmpvector <- c(a[x], b[x], c[x], d[x], rad[r])
  mymatrix[row.number,] <- tmpvector
  })
})
View(mymatrix)

With the code as now written, the resulting matrix is still blank.

If I write this simple example as a for loop

mymatrix <- matrix(,nrow=18, ncol=5)

a <- 1:6
b <- rnorm(6, 5, 10)
c <- rnorm(6, 100, 20)
d <- rnorm(6, 20, 20)

rad <- c(100,200,300)

for (r in 1:3) {
  for (x in 1:6) {
    row.number <- (r-1)*6+x 
    tmpvector <- c(a[x], b[x], c[x], d[x], rad[r])
    mymatrix[row.number,] <- tmpvector
  }
} 
View(mymatrix)

then the matrix fills with values as I expect. I apologise if I am making a simple blunder: I am very new to these loops!

NB I would also be open to creating a continuous list of this data, which I could then transform into a more useful format!

Community
  • 1
  • 1
Nematode
  • 35
  • 6

2 Answers2

1

Using lapply is not very natural in this situation. You don't need a loop at all for the creation of such a matrix, you can use R's recycling characteristics.

mymatrix <- cbind(a, b, c, d, rep(c(100,200,300), each = 6))
Edwin
  • 3,184
  • 1
  • 23
  • 25
  • It's true that lapply isn't necessary to create the matrix in my example. However, lapply is necessary for the iterative geospatial processing tasks in my complete script, which are generating the output that I must organise into a dataframe or matrix. To be honest, creating a list would also be sufficient for me, because I could then transform that list into a more useful format. Thanks for your suggestion, @Edwin ! – Nematode Jul 12 '16 at 13:25
0

If you really want to do it with lapply, here a quite ugly way to do it (and you were nearly there yourself):

set.seed(123)
#we don't really need to initialise the matrix anymore
#mymatrix <- matrix(,nrow=18, ncol=5)

a <- 1:6
b <- rnorm(6, 5, 10)
c <- rnorm(6, 100, 20)
d <- rnorm(6, 20, 20)
rad <- c(100,200,300)

#Generate the list of rows:
rowList<-lapply(1:3,function(r){
                    lapply(1:6,function(x){
                               #data processing
                               #row.number <- (r-1)*6+x #actually this line is unnecessary
                               tmpvector <- c(a[x], b[x], c[x], d[x], rad[r])
                    })
})

#creation of mymatrix -- method 1
mymatrix<-as.matrix(data.frame(rowList))
colnames(mymatrix)<-NULL #since you probably don't want the ugly output
mymatrix<-t(mymatrix)   

###   OR 
#creation of my matrix -- method2 (with do.call and rbind)
do.call(rbind,sapply(rowList,matrix))

The problem with your initial approach (i.e. to try to change the matrix within the lapply) is that at the end of each iteration you return the last result you have created: the creation of the current row and as there is no error, message or warning created, you don't have any output.

mymatrix stays as it was before the lapply loop, since all the processing was done inside {and } and was also not saved.

BTW, if you want to do anything with the output of lapply, you should save them in an object (or plug them directly in another function, which I won't recommend if you are not at ease with the internal logic of lapply).

Hopefully, my explanation is not too convoluted and a little bit off-topic, but a good place to start with the *apply family and equivalent: R Grouping functions: sapply vs. lapply vs. apply. vs. tapply vs. by vs. aggregate

Community
  • 1
  • 1
Mitra
  • 655
  • 8
  • 16