How to Load a Matlab Struct into a R Data Frame

How to import Matlab table ('cell' structure) to R dataframe while conserving proper structure/order?

I still don't know why MAT v5 needs to import tables to lists, but I unexpectedly found a solution!

The function below will easily extract a specific row from that type of list, where list is your list, row is the row you want to extract, and nrow is the total number of rows (given that you know these details):

matlab.row <- function(list,row,nrow) {
unlist(list[seq(row, length(list), nrow)]) # This will take every nth element starting from desired row
}

matlab.row(mylist,1,4)
"2" "34" "17"
matlab.row(mylist,2,4)
"32" "43"
matlab.row(mylist,3,4)
"C" "D" "A" "F" "G" "I"
matlab.row(mylist,4,4)
"455"

In order to get the full data frame, I had to tweak the function some more, where list is your list, max.len is the length of the longest row (max number of items), and nrow is your total number of rows:

matlab.df <- function(list,max.len,nrow) {
matlab.row <- function(list,row,nrow) { # We reuse the function we just made earlier
unlist(list[seq(row, length(list), nrow)])
}
listA <- vector('list', nrow) # Precreates list
for (i in 1:nrow) {
listA[i] <- list(c(matlab.row(list,i,nrow), # Combines output from last function to NAs on next line
rep(NA, max.len - length(matlab.row(list,i,nrow))))) # Fills the remaining columns with NAs (very important part!)
}
df <- do.call(rbind,listA) # Binds elements together from the list we created as rows
df # Prints dataframe
}

matlab.df(list = mylist, max.len = 6, nrow = 4)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] "2" "34" "17" NA NA NA
[2,] "32" "43" NA NA NA NA
[3,] "C" "D" "A" "F" "G" "I"
[4,] "455" NA NA NA NA NA

I found the solution thanks to a combination of these threads: 1, 2, 3, and 4.

R - Help converting nested lists(?) to data.frame

Why not just extract from that list object?

dat <- as.data.frame( mlab$ DATA[1:15]) 
colnames(dat) <- unlist( mlab$ DATA[16] )

(It may display better if you take the transpose ( ?t ) and use a wide screen with options(width=150) ... and use round to 3 places.

round( t(dat) , 3)

R building large data frame from file import

Taking into account Roland's suggestion, here is, I guess, a bad way to do it with for loops. I separated the subjects because the object got too large.

subdirs <- list.dirs(".")

for (this_subd in 2:length(subdirs)) {
erpdata <- array(dim = c(200,16,256)) # ERP array
targets <- array(dim = c(200,1)) # Target array
# look for all mat-files in that directory
filelist <- list.files(path = subdirs[this_subd], full.names = FALSE,
pattern = "^.*.mat$",
ignore.case = TRUE, recursive = TRUE,
include.dirs = FALSE)

# combine current subdir path
filelist <- paste(subdirs[this_subd],filelist,sep="/")

# Anonymous function to work over each file and resave as R data
filedatas <- lapply(filelist, function(x) {
curdata <- readMat(con = x)
return(curdata)
})

for (this_file in 2:length(filedatas)) {
this_erp <- filedatas[][[this_file]]$eeg
this_tgt <- this_erp[,,1]$TGT
this_erp <- array(this_erp[,,1]$ERP,dim = c(200,16,256))
erpdata <- abind(erpdata,this_erp,along=1)
targets <- rbind(targets,this_tgt)
}

# Permute the data into samples X channels X trials
erpdata <- aperm(erpdata,c(3,2,1))
# Remove NAs from originally initializing array
erpdata <- array(erpdata[!is.na(erpdata)],dim = dim(erpdata))
targets <- array(targets[!is.na(targets)],dim = dim(targets))
targets <- as.factor(targets) # convert to categorical variable

save(erpdata,targets,
file = paste(subdirs[this_subd],"/",
substring(subdirs[this_subd],first=3),
"unifieddata.Rdata",
sep = "")
)
# cleanup to save memory
rm(erpdata,targets,this_erp,this_tgt)
}

In R, how to convert a list that contains a list and numeric elements into a data frame

Solution (thanks to Ian Campbell):

Note: The column names are wonky, but the data were successfully extracted and exported into a .CSV file!

library(R.matlab)
library(tidyr)

cats <- readMat("cats.mat")

cats2 <- cats$catlist

cats3 <- lapply(cats2, unlist, use.names=TRUE)

cats_for_export <- as.data.frame(cats3)

write.csv(cats_for_export, file="cats.csv")


Related Topics



Leave a reply



Submit