converting a matrix to a list - list

Suppose I have a matrix foo as follows:
foo <- cbind(c(1,2,3), c(15,16,17))
> foo
[,1] [,2]
[1,] 1 15
[2,] 2 16
[3,] 3 17
I'd like to turn it into a list that looks like
[[1]]
[1] 1 15
[[2]]
[1] 2 16
[[3]]
[1] 3 17
You can do it as follows:
lapply(apply(foo, 1, function(x) list(c(x[1], x[2]))), function(y) unlist(y))
I'm interested in an alternative method that isn't as complicated. Note, if you just do apply(foo, 1, function(x) list(c(x[1], x[2]))), it returns a list within a list, which I'm hoping to avoid.

Here's a cleaner solution:
as.list(data.frame(t(foo)))
That takes advantage of the fact that a data frame is really just a list of equal length vectors (while a matrix is really a vector that is displayed with columns and rows...you can see this by calling foo[5], for instance).
You could also do this, although it isn't much of an improvement:
lapply(1:nrow(foo), function(i) foo[i,])

library(plyr)
alply(foo, 1)

Related

Faster alternatives to outer

I'm trying to make the following call to outer() substantially faster. Parallelizing via foreach is still prohibitively slow, so I'd like to attempt calling this in C++ using Rcpp but would love to hear any faster alternative.
Given a matrix mat and a list of matrix colnames col.list I am summarizing mat as such.
mycall <- function(mat, col.list) {
outer(
rownames(mat),
col.list,
Vectorize(function(x,y) {
mean(mat[x,y])
})
)
}
For instance:
set.seed(123)
mat <- matrix(rnorm(100),nrow=10)
rownames(mat) <- letters[1:10]
colnames(mat) <- LETTERS[1:10]
mat
A B C D E F G H I J
a -0.56047565 1.2240818 -1.0678237 0.42646422 -0.69470698 0.25331851 0.37963948 -0.4910312 0.005764186 0.9935039
b -0.23017749 0.3598138 -0.2179749 -0.29507148 -0.20791728 -0.02854676 -0.50232345 -2.3091689 0.385280401 0.5483970
c 1.55870831 0.4007715 -1.0260044 0.89512566 -1.26539635 -0.04287046 -0.33320738 1.0057385 -0.370660032 0.2387317
d 0.07050839 0.1106827 -0.7288912 0.87813349 2.16895597 1.36860228 -1.01857538 -0.7092008 0.644376549 -0.6279061
e 0.12928774 -0.5558411 -0.6250393 0.82158108 1.20796200 -0.22577099 -1.07179123 -0.6880086 -0.220486562 1.3606524
f 1.71506499 1.7869131 -1.6866933 0.68864025 -1.12310858 1.51647060 0.30352864 1.0255714 0.331781964 -0.6002596
g 0.46091621 0.4978505 0.8377870 0.55391765 -0.40288484 -1.54875280 0.44820978 -0.2847730 1.096839013 2.1873330
h -1.26506123 -1.9666172 0.1533731 -0.06191171 -0.46665535 0.58461375 0.05300423 -1.2207177 0.435181491 1.5326106
i -0.68685285 0.7013559 -1.1381369 -0.30596266 0.77996512 0.12385424 0.92226747 0.1813035 -0.325931586 -0.2357004
j -0.44566197 -0.4727914 1.2538149 -0.38047100 -0.08336907 0.21594157 2.05008469 -0.1388914 1.148807618 -1.0264209
col.list <- replicate(5, sample(colnames(mat),sample(10,1)), simplify = F)
col.list
[[1]]
[1] "I" "H" "F" "C"
[[2]]
[1] "H" "C" "E" "D"
[[3]]
[1] "F" "A" "B" "C"
[[4]]
[1] "I" "G" "H" "F"
[[5]]
[1] "B" "F" "A" "D" "J"
mycall(mat, col.list)
[,1] [,2] [,3] [,4] [,5]
[1,] -0.32494304 -0.45677441 -0.03772476 0.03692275 0.46737855
[2,] -0.54260254 -0.75753314 -0.02922133 -0.61368967 0.07088301
[3,] -0.10844910 -0.09763415 0.22265121 0.06475016 0.61009334
[4,] 0.14372171 0.40224937 0.20522554 0.07130067 0.36000416
[5,] -0.43982636 0.17912380 -0.31934091 -0.55151435 0.30598183
[6,] 0.29678266 -0.27389757 0.83293885 0.79433814 1.02136588
[7,] 0.02527506 0.17601171 0.06195023 -0.07211925 0.43025291
[8,] -0.01188734 -0.39897791 -0.62342288 -0.03697956 -0.23527315
[9,] -0.28972770 -0.12070775 -0.24994491 0.22537340 -0.08066115
[10,] 0.61991819 0.16277087 0.13782578 0.81898563 -0.42188074
You could try:
sapply(col.list, function(v) rowMeans(mat[, v]))
I suspect the reason your solution is slow is Vectorize: it's a nice way to transform a scalar function into a vectorized function, but it has a huge cost: since it's based on mapply, it will call the function on each element, one by one. That is, one call to mean for each entry. If the outer result is large, that's going to be very costly. Instead, with the solution above, the code is at least vectorized in one direction, thanks to rowMeans.

how to combine vectors with different length within a list in R?

I have a problem when combining the following vectors included in the list:
x <- list(as.numeric(c(1,4)),as.numeric(c(3,19,11)))
names (x[[1]]) <- c("species.A","species.C")
names (x[[2]]) <- c("species.A","species.B","species.C")
which gives the following list:
>x
>[[1]]
>species.A species.C
> 1 4
>[[2]]
>species.A species.B species.C
> 3 19 11
combining them using the do.call function:
y<- do.call(cbind,x)
gives:
>y
> [,1] [,2]
> species.A 1 3
> species.B 4 19
> species.C 1 11
while I would like to obtain this:
> [,1] [,2]
> species.A 1 3
> species.B NA 19
> species.C 4 11
You need to give R a bit more help, by first preparing the particular vectors, all of the same length, that you eventually want to cbind together. Otherwise (as you've seen) R uses its usual recycling rules to fill out the matrix.
Try something like this:
spp <- paste("species", c("A", "B", "C"), sep=".")
x2 <- lapply(x, FUN=function(X) X[spp])
mat <- do.call("cbind", x2)
row.names(mat) <- spp
mat
[,1] [,2]
species.A 1 3
species.B NA 19
species.C 4 11
EDIT: As Brian mentions in comments, this could be made a bit more compact (but at the expense of some readability). Which one you use is just a matter of taste:
mat <- do.call("cbind", lapply(x, "[", spp))
row.names(mat) <- spp
It looks like you're actually trying to do a merge. As such, merge will work. You just have to tell it to merge on the names, and to keep all rows.
do.call(merge, c(x, by=0, all=TRUE)) # by=0 and by="row.names" are the same
(This will create a data frame rather than a matrix, but for most purposes that shouldn't be an issue.)
merge(x = x[[1]], y = x[[2]], by = "names", all.y = TRUE)

How to expand a list with NULLs up to some length?

Given a list whose length <= N, what is the best / most efficient way to fill it up with trailing NULLs up to length (so that it has length N).
This is something which is a one-liner in any decent language, but I don't have a clue how to do it (efficiently) in a few lines in R so that it works for every corner case (zero length list etc.).
Let's keep it really simple:
tst<-1:10 #whatever, to get a vector of length 10
tst<-tst[1:15]
Try this :
> l = list("a",1:3)
> N = 5
> l[N+1]=NULL
> l
[[1]]
[1] "a"
[[2]]
[1] 1 2 3
[[3]]
NULL
[[4]]
NULL
[[5]]
NULL
>
How about this ?
> l = list("a",1:3)
> length(l)=5
> l
[[1]]
[1] "a"
[[2]]
[1] 1 2 3
[[3]]
NULL
[[4]]
NULL
[[5]]
NULL
Directly editing the list's length appears to be the fastest as far as I can tell:
tmp <- vector("list",5000)
sol1 <- function(x){
x <- x[1:10000]
}
sol2 <- function(x){
x[10001] <- NULL
}
sol3 <- function(x){
length(x) <- 10000
}
library(rbenchmark)
benchmark(sol1(tmp),sol2(tmp),sol3(tmp),replications = 5000)
test replications elapsed relative user.self sys.self user.child sys.child
1 sol1(tmp) 5000 2.045 1.394952 1.327 0.727 0 0
2 sol2(tmp) 5000 2.849 1.943383 1.804 1.075 0 0
3 sol3(tmp) 5000 1.466 1.000000 0.937 0.548 0 0
But the differences aren't huge, unless you're doing this a lot on very long lists, I suppose.
I'm sure there are shorter ways, but I would be inclined to do:
l <- as.list(1:10)
N <- 15
l <- c(l, as.list(rep(NA, N - length(l) )))
Hi: I'm not sure if you were talking about an actual list but, if you were, below will work. It works because, once you access the element of a vector ( which is a list is ) that is not there, R expands the vector to that length.
length <- 10
temp <- list("a","b")
print(temp)
temp[length] <- NULL
print(temp)

Combine rownames from different lists in a dataframe

I have a question about lists in R. I have a list within 16 list containing a list with variables like this:
x
[[1]]
A 1 3
B 4 2
[[2]]
C 23 4
D 9 22
E 4 54
The A,B,C and D are rownames in the lists. Now I want to create a file that paste only the rownames in a dataframe. Each row in the dataframe contains 1 list in the total list.
A B
C D E
Can anyone help me with this? I thought maybe someting like do.call(rbind, rownames(x))
EDIT! 05-08-2011
Is there a way to save the rownames list by list? So in the end there are no NA's in the data and the data is unequal?
Thank you all!
Making an assumption about the nature of x, if we use:
x <- list(matrix(c(1,4,3,2), ncol = 2,
dimnames = list(c("A","B"), NULL)),
matrix(c(23,9,4,4,22,54), ncol = 2,
dimnames = list(c("C","D","E"), NULL)))
which gives:
> x
[[1]]
[,1] [,2]
A 1 3
B 4 2
[[2]]
[,1] [,2]
C 23 4
D 9 22
E 4 54
Then
> lapply(x, rownames)
[[1]]
[1] "A" "B"
[[2]]
[1] "C" "D" "E"
seems the only plausible answer. Unless we pad the ("A","B") vector with something, we can't use a matrix or a data frame because the component lengths do not match. Hence one of the reasons the do.call() idea fails:
> do.call(rbind, rownames(x))
Error in do.call(rbind, rownames(x)) : second argument must be a list
> do.call(rbind, lapply(x, rownames))
[,1] [,2] [,3]
[1,] "A" "B" "A"
[2,] "C" "D" "E"
Warning message:
In function (..., deparse.level = 1) :
number of columns of result is not a multiple of vector length (arg 1)
To pad the result with NA and get a data frame, we could do:
out <- lapply(x, rownames)
foo <- function(x, max, repl = NA) {
if(length(x) == max)
out <- x
else {
out <- rep(repl, max)
out[seq_along(x)] <- x
}
out
}
out <- lapply(out, foo, max = max(sapply(out, length)))
(out <- do.call(rbind, out))
The last line gives:
> (out <- do.call(rbind, out))
[,1] [,2] [,3]
[1,] "A" "B" NA
[2,] "C" "D" "E"
If you want that nicely printed, then
> print(format(out), quote = FALSE)
[,1] [,2] [,3]
[1,] A B NA
[2,] C D E
is an option inside R.
This should do it:
lapply(x, function(curdfr){paste(rownames(curdfr))})
This results in a vector with each element the space-separated rownames of the elements of the list.
Your sample data:
x <- list(
matrix(c(1,4,3,2), nrow = 2, dimnames = list(LETTERS[1:2])),
matrix(c(23,9,4,4,22,54), nrow = 3, dimnames = list(LETTERS[3:5]))
)
What you want:
unlist(lapply(x, rownames))
Or, if you are keen on do.call, then this is equivalent:
do.call(c, lapply(x, rownames))

converting a matrix of lists to a regular matrix

Take the following code:
foo <- list()
foo[[1]] <- list(a=1, b=2)
foo[[2]] <- list(a=11, b=22)
foo[[3]] <- list(a=111, b=222)
result <- do.call(rbind, foo)
result[,'a']
In this case, result[,'a'] shows a list. Is there a more elegant way such that result is a "regular" matrix of vectors? I imagine there are manual ways of going about this, but I was wondering if there was an obvious step that I was missing.
do.call on lists is very elegant, and fast. In fact do.call(rbind, my.list) once saved my ass when I needed to combine a huge list. It was by far the fastest solution.
To solve your problem, maybe something like:
do.call(rbind, lapply(foo, unlist))
> result.2 <- do.call(rbind, lapply(foo, unlist))
> result.2
a b
[1,] 1 2
[2,] 11 22
[3,] 111 222
> result.2[, 'a']
[1] 1 11 111
>
One possible solution is as follows (but am interested in alternatives):
new.result <- matrix(unlist(result), ncol=ncol(result),
dimnames=list(NULL, colnames(result)))