0
votes

I have a named data.frame that contains 10 items with three columns each. Each item in the data.frame looks like this:

$RandArcBo1
$RandArcBo1$x
 [1]  -97.5 -174.5  156.5 -172.5  111.5 -132.5  142.5  115.5  146.5  171.5  151.5  162.5  168.5 -153.5  129.5  123.5

$RandArcBo1$y
 [1] 86.56732 79.56732 59.56732 77.56732 77.56732 75.56732 58.56732 82.56732 84.56732 74.56732 78.56732 74.56732 76.56732
[14] 77.56732 78.56732 84.56732

$RandArcBo1$Species
[1] "RandArcBo1"

I would like to convert this to one data.table with the columns rearranged. My current approach to this is:

tempList <- c()
for (j in seq_along(dfList)){
   tempList <- append(tempList, as.data.table(c(dfList[[j]][3], dfList[[j]][1], dfList[[j]][2])))
}
assign(paste(name, "RandPoints", sep = ""), rbindlist(tempList))

However, when I run this I get the following error:

Error in rbindlist(tempList) : 
  Item 1 of list input is not a data.frame, data.table or list

Is there a way to solve this error and use rbindlist, or perhaps a way to iteratively add rows to a data.table? I've tried that approach as well, and have not been able to solve the problem of how to create an empty data.table to add rows to.

For more information, here is my full script:

#You will need to collect the following in a folder specified as the working directory:
#   ASCII layers representing the Ms for each species to use as a mask
#   a file named "NumbLoc.csv" with names of ASCII layers and the number of points to be randomly generated in each
require(raster)
require(dismo)
require(SDMTools)
require(data.table)
#Get files
fileList <- list.files(pattern="*.asc", full.names=TRUE)
numbPoints <- read.csv("NumbLoc.csv", header = TRUE, sep = ",", stringsAsFactors=FALSE)
nPoints<-as.data.frame(numbPoints)
#Loop through files in specified folder
for (a in 1:length(fileList)){
  name <- substr(fileList[a], 3, 7 )
  print(name)
  #Reads in ASCII, changes it to raster
  #Raster will serve as a mask for generation of random points
  assign(name,raster(fileList[a]))
  #starts/clears a list of dataframes for each species
  dfList <- c()
  #loops through however many iterations you want, generating random points as specified in csv file
  for(i in 1:10){
    nameRand <- paste("Rand", substr(fileList[a], 3, 7),i, sep = "")
    dfList[[nameRand]]=c(as.data.frame(randomPoints(get(name), nPoints$Number[nPoints$Species==name])))
  }
  #adds a column in each data frame specifying the name of the randomized run
  #converts data frame to a series of data table with columns in the correct order
  tempList <- c()
  for (j in seq_along(dfList)){
    dfList[[j]]$Species <- names(dfList[j])
    #assign(tempListName, as.data.table(c(dfList[[j]][3], dfList[[j]][1], dfList[[j]][2])))
    tempList <- append(tempList, as.data.table(c(dfList[[j]][3], dfList[[j]][1], dfList[[j]][2])))
  }
  assign(paste(name, "RandPoints", sep = ""), rbindlist(tempList))
}

The data frame looks like this:

> dput(head(dfList))
structure(list(RandArcBo1 = structure(list(x = c(-97.5, -174.5, 
156.5, -172.5, 111.5, -132.5, 142.5, 115.5, 146.5, 171.5, 151.5, 
162.5, 168.5, -153.5, 129.5, 123.5), y = c(86.567321777, 79.567321777, 
59.567321777, 77.567321777, 77.567321777, 75.567321777, 58.567321777, 
82.567321777, 84.567321777, 74.567321777, 78.567321777, 74.567321777, 
76.567321777, 77.567321777, 78.567321777, 84.567321777), Species = "RandArcBo1"), .Names = c("x", 
"y", "Species")), RandArcBo2 = structure(list(x = c(170.5, -160.5, 
150.5, 165.5, 78.5, 74.5, -161.5, -129.5, -134.5, -164.5, 166.5, 
-169.5, -156.5, -163.5, 89.5, 150.5), y = c(86.567321777, 76.567321777, 
57.567321777, 70.567321777, 77.567321777, 78.567321777, 74.567321777, 
74.567321777, 72.567321777, 80.567321777, 84.567321777, 85.567321777, 
78.567321777, 80.567321777, 76.567321777, 83.567321777), Species = "RandArcBo2"), .Names = c("x", 
"y", "Species")), RandArcBo3 = structure(list(x = c(179.5, 149.5, 
-153.5, 129.5, 158.5, 169.5, 131.5, -147.5, -140.5, 128.5, 173.5, 
-172.5, -177.5, -91.5, -143.5, 87.5), y = c(63.567321777, 57.567321777, 
72.567321777, 80.567321777, 50.567321777, 58.567321777, 76.567321777, 
72.567321777, 72.567321777, 81.567321777, 58.567321777, 88.567321777, 
88.567321777, 72.567321777, 73.567321777, 82.567321777), Species = "RandArcBo3"), .Names = c("x", 
"y", "Species")), RandArcBo4 = structure(list(x = c(114.5, 156.5, 
76.5, 171.5, -137.5, -140.5, -142.5, 135.5, 152.5, -136.5, -167.5, 
-131.5, 94.5, 154.5, -78.5, -124.5), y = c(83.567321777, 80.567321777, 
78.567321777, 57.567321777, 69.567321777, 73.567321777, 80.567321777, 
84.567321777, 52.567321777, 70.567321777, 67.567321777, 70.567321777, 
85.567321777, 85.567321777, 84.567321777, 81.567321777), Species = "RandArcBo4"), .Names = c("x", 
"y", "Species")), RandArcBo5 = structure(list(x = c(-162.5, 79.5, 
179.5, 166.5, 81.5, 115.5, 155.5, 84.5, 163.5, 166.5, 178.5, 
-119.5, -157.5, 128.5, 118.5, 164.5), y = c(77.567321777, 82.567321777, 
74.567321777, 55.567321777, 81.567321777, 81.567321777, 52.567321777, 
75.567321777, 51.567321777, 73.567321777, 61.567321777, 75.567321777, 
77.567321777, 81.567321777, 84.567321777, 55.567321777), Species = "RandArcBo5"), .Names = c("x", 
"y", "Species")), RandArcBo6 = structure(list(x = c(-148.5, 123.5, 
-130.5, 164.5, -129.5, 168.5, -106.5, 144.5, 166.5, -127.5, -135.5, 
96.5, -95.5, 76.5, -99.5, -144.5), y = c(71.567321777, 78.567321777, 
85.567321777, 70.567321777, 76.567321777, 79.567321777, 85.567321777, 
58.567321777, 56.567321777, 78.567321777, 74.567321777, 76.567321777, 
86.567321777, 73.567321777, 82.567321777, 75.567321777), Species = "RandArcBo6"), .Names = c("x", 
"y", "Species"))), .Names = c("RandArcBo1", "RandArcBo2", "RandArcBo3", 
"RandArcBo4", "RandArcBo5", "RandArcBo6"))
2
I'm worried that you are confused, because (just as in your last question) you seem to be referring to objects as data frames that are not, in fact, data frames. You are starting with a list, a nested listed it looks like. Are you sure that you really need to use the data.table package? Why can't you simply convert these to data frames using as.data.frame?joran
dput(head(your_data_object)) please - it's very unclear what you want or haveeddi
It is most definitely a data frame. I apologize for being unclear, I didn't want to post the whole script and resulting data frame, as they're a bit big. I have edited my post to give you the full picture.Hannah O.
No. You are mistaken. The objects in dfList are not data frames.joran
They are lists. Use str to determine what objects actually are. You misusing the function c. It is used for concatenating vectors. Vectors. I will attempt to re-write this as best I can.joran

2 Answers

4
votes

This is the solution to your immediate problem, but I'd recommend rethinking your initial data structure to begin with:

 rbindlist(lapply(dfList, as.data.table))
2
votes

Here's an attempt at untangling this. But you've really made this far too complicated.

#read.csv returns a data frame. No need for this.
nPoints<-as.data.frame(numbPoints)

#Loop through files in specified folder
for (a in 1:length(fileList)){
  name <- substr(fileList[a], 3, 7 )
  print(name)
  #Reads in ASCII, changes it to raster
  #Raster will serve as a mask for generation of random points
  assign(name,raster(fileList[a]))
  #starts/clears a list of dataframes for each species
  # If it's supposed to be a list, don't use c()!
  dfList <- list()
  #loops through however many iterations you want, generating random points as specified in csv file
  for(i in 1:10){
    nameRand <- paste("Rand", substr(fileList[a], 3, 7),i, sep = "")
    #Again, don't use c()!
    dfList[[nameRand]] <- as.data.frame(randomPoints(get(name), nPoints$Number[nPoints$Species==name]))
  }
  #adds a column in each data frame specifying the name of the randomized run
  #converts data frame to a series of data table with columns in the correct order
  tempList <- list()
  for (j in seq_along(dfList)){
    dfList[[j]]$Species <- names(dfList[j])
    #assign(tempListName, as.data.table(c(dfList[[j]][3], dfList[[j]][1], dfList[[j]][2])))
    #No need to coerce it _again_ if it's already a data frame. Just
    # reorder the columns the easy way.
    tempList <- append(tempList, dfList[[j]][,c(3,1,2)])
  }
  assign(paste(name, "RandPoints", sep = ""), do.call(rbind,tempList))
}

More generally, most of your troubles are coming from your use of functions like assign and get. These should almost never be used in R. There really is no need. For example, the first part of your script can essentially be accomplished in 4 lines:

#Loop over file list, calling raster on each
rasterList <- lapply(fileList,raster)
#Assign all the names at once.
names(rasterList) <- substr(fileList,3,7)

#Need to make sure that the rasters are in the same order as the values
# in nPoints$Number
dfList <- mapply(randomPoints,mask = rasterList,n = nPoints$Number)
names(dfList) <- paste0("Rand",names(rasterList))

At this point, I would simply re-combine the data frames into one:

ns <- sapply(dfList,nrow)
out <- do.call(dfList,rbind)

and then create the Species column after the fact via something like this:

out$Species <- rep(paste0("Rand",names(rasterList)),times = ns)