I'm trying to massage some data from Matlab into R. The matlab file has a "struct array" which when imported into R using the R.matlab package, becomes an R list with 3+ dimensions, the first of which corresponds to the structure fields, with corresponding row names, and the second and third+ dimensions correspond to the dimensions of the original struct array (as matlab arrays always have 2+ dimensions). For example a 1x1 matlab struct array with three fields becomes: > data , , 1 [,1] trials List,1002 beforeRun List,8 afterRun List,8 If I load two data files, I would want to concatenate them into a single list. cbind() doesn't preserve the row names, possibly because the array has three dimensions? > cbind(data1, data2) data1 data2 [1,] List,1002 List,479 [2,] List,8 List,8 [3,] List,8 List,8 Then I looked into abind(), which is even more puzzling: it preserves the names and dimensions correctly, but converts the entries into strings?! > abind(list(data1, data2), along=2, force.array=FALSE) , , 1 [,1] [,2] trials "0" "1" beforeRun "2079647.50207592" "0" afterRun "1" "0" Is there a quick way to accomplish the effect I want? I want an output that looks like: > somebind(data1, data2, along=2) , , 1 [,1] [,2] trials List,1002 List,479 beforeRun List,8 List,8 afterRun List,8 List,8 Cheers, Peter
On Sep 2, 2009, at 10:50 PM, Peter Meilstrup wrote:> I'm trying to massage some data from Matlab into R. The matlab file > has a "struct array" which when imported into R using the R.matlab > package, becomes an R list with 3+ dimensions, the first of which > corresponds to the structure fields, with corresponding row names, > and the second and third+ dimensions correspond to the dimensions of > the original struct array (as matlab arrays always have 2+ > dimensions). For example a 1x1 matlab struct array with three fields > becomes: > > > data > , , 1 > > [,1] > trials List,1002 > beforeRun List,8 > afterRun List,8 > > If I load two data files, I would want to concatenate them into a > single list. cbind() doesn't preserve the row names, possibly > because the array has three dimensions?No. cbind makes matrices. Arrays and matrices are required to have all elements of the same type, so any coercive function returning an array would force the elements to have the "lowest common denominator" type, which is "list" in this case.> > > cbind(data1, data2) > data1 data2 > [1,] List,1002 List,479 > [2,] List,8 List,8 > [3,] List,8 List,8 > > Then I looked into abind(), which is even more puzzling: it > preserves the names and dimensions correctly, but converts the > entries into strings?!Must be from a non-base package or a devel version. I get > abind Error: object 'abind' not found> > > abind(list(data1, data2), along=2, force.array=FALSE) > , , 1 > > [,1] [,2] > trials "0" "1" > beforeRun "2079647.50207592" "0" > afterRun "1" "0" > > Is there a quick way to accomplish the effect I want? I want an > output that looks like: > > > somebind(data1, data2, along=2)How about: list(data1, data2) ... or in this case, because you are starting with two list objects, you could get the same effect with: c(data1, data2)> , , 1 > > [,1] [,2] > trials List,1002 List,479 > beforeRun List,8 List,8 > afterRun List,8 List,8 > > Cheers, > Peter > > ___________David Winsemius, MD Heritage Laboratories West Hartford, CT
Almost certainly, abind is what you need for the task. Please dput() your matlab objects and send that to the list. That will make your example reproducible. Rich
On Sep 2, 2009, at 8:47 PM, Richard M. Heiberger wrote:> Almost certainly, abind is what you need for the task. > > Please dput() your matlab objects and send that to the list. > That will make your example reproducible. > > RichFrom the documentation and behavior, abind seems to really not want to work on lists. Here is a dput of some list arrays that demonstrate the problem. > data1 , , 1 [,1] [,2] foo 1 4 bar Numeric,3 Numeric,3 baz "quux" "n" > dput(data1) structure(list(1L, c(3, 4, 5), "quux", 4L, c(3, 5, 9), "n"), .Dim = c(3L, 2L, 1L), .Dimnames = list(c("foo", "bar", "baz"), NULL, NULL)) > data2 , , 1 [,1] foo 1 bar Numeric,5 baz "qux" > dput(data2) structure(list(1, c(2, 3, 4, 6, 9), "qux"), .Dim = c(3L, 1L, 1L), .Dimnames = list(c("foo", "bar", "baz"), NULL, NULL)) abind() decides that it wants to coerce all lists into character, among other failures (e.g. how did "quux" wind up in the second row?:) > library(abind) > abind(list(data1,data2), along=2, force.array=FALSE) , , 1 [,1] [,2] [,3] foo "1" "5" "3" bar "3" "quux" "5" baz "4" "4" "9" What I want to happen: > goal , , 1 [,1] [,2] [,3] [1,] 1 4 1 [2,] Numeric,3 Numeric,3 Numeric,5 [3,] "quux" "n" "qux" > dput(goal) structure(list(1L, c(3, 4, 5), "quux", 4L, c(3, 5, 9), "n", 1, c(2, 3, 4, 6, 9), "qux"), .Dim = c(3L, 3L, 1L)) --Peter
On Thu, Sep 3, 2009 at 5:50 AM, Peter Meilstrup <peter.meilstrup@gmail.com>wrote:> I'm trying to massage some data from Matlab into R. The matlab file has a > "struct array" which when imported into R using the R.matlab package, > becomes an R list with 3+ dimensions, the first of which corresponds to the > structure fields, with corresponding row names, and the second and third+ > dimensions correspond to the dimensions of the original struct array (as > matlab arrays always have 2+ dimensions). For example a 1x1 matlab struct > array with three fields becomes: > > > data > , , 1 > > [,1] > trials List,1002 > beforeRun List,8 > afterRun List,8 >This doesn't look like a list at all -- rather, it seems like a 3-dimensional array which has lists as its elements. But it seems that the last dimension of your array is not actually used, so can't you do just cbind(data1[,,1], data2[,,1]) ? Or if you really need that empty dimension, use something like array(cbind(data1,data2), dim=c(3,2,1), dimnames=rownames(data1[,,1])) (tried it with abind I just downloaded, and it says this: "Error in abind(x, x2, along = 3, force.array = FALSE) : can only supply one list-valued argument for ...". Maybe it's a recent change) KK> If I load two data files, I would want to concatenate them into a single > list. cbind() doesn't preserve the row names, possibly because the array has > three dimensions? > > > cbind(data1, data2) > data1 data2 > [1,] List,1002 List,479 > [2,] List,8 List,8 > [3,] List,8 List,8 > > Then I looked into abind(), which is even more puzzling: it preserves the > names and dimensions correctly, but converts the entries into strings?! > > > abind(list(data1, data2), along=2, force.array=FALSE) > , , 1 > > [,1] [,2] > trials "0" "1" > beforeRun "2079647.50207592" "0" > afterRun "1" "0" > > Is there a quick way to accomplish the effect I want? I want an output that > looks like: > > > somebind(data1, data2, along=2) > , , 1 > > [,1] [,2] > trials List,1002 List,479 > beforeRun List,8 List,8 > afterRun List,8 List,8 > > Cheers, > Peter > > ______________________________________________ > R-help@r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide > http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >[[alternative HTML version deleted]]
Peter, Thank you for the dput values. Kenn points out that result <- cbind(data1[,,1], data2[,,1]) dim(result) <- c(3,3,1) gets what you want. We wrote abind to bind atomic arrays and/or data.frames. The list feature, which is interfering with your usage, was designed to simplify calling sequences. I think if we cancel that feature (effectively replacing it with do.call) then it should be possible to include your case of non-atomic lists within abind. Is this worth doing? Rich