apply function to elements over a list - r

Sorry for the simple question but I can't think of a good way to take functions elements of a list of data frames. I am sure there is something within the plyr/reshape2 packages but I just can't think of it.
For example I have a list A as follows:
>A
[[1]]
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 1 1 1 1 1 1 1 1 1 1
[2,] 1 1 1 1 1 1 1 1 1 1
[3,] 1 1 1 1 1 1 1 1 1 1
[4,] 1 1 1 1 1 1 1 1 1 1
[5,] 1 1 1 1 1 1 1 1 1 1
[[2]]
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 2 2 2 2 2 2 2 2 2 2
[2,] 2 2 2 2 2 2 2 2 2 2
[3,] 2 2 2 2 2 2 2 2 2 2
[4,] 2 2 2 2 2 2 2 2 2 2
[5,] 2 2 2 2 2 2 2 2 2 2
Say I want to take the mean across the corresponding elements of the matrices in the list. One way to do this would be
Reduce("+",A)/length(A)
I can't seem to feed Reduce() more complex functions and assume there is a better way in general.

In this case, maybe you're better off with your data in an array rather than a list?
#Recreate data
A <- list(a=matrix(1,5,10),b=matrix(2,5,10))
#Convert to array
A1 <- array(do.call(cbind,A),dim = c(5,10,2))
#Better way to convert to array
require(abind)
A1 <- abind(A,along = 3)
#Now we can simply use apply
apply(A1,c(1,2),mean)

Maybe do.call?
do.call(`+`, A)/length(A)
Or if you really don't want to abind it into a larger matrix,
array(sapply(seq_along(A[[1]]), function(i) mean(sapply(A,`[`,i))),
dim=dim(A[[1]]))

Related

Filter by a column value in a 3D matrix in R

Edit: I've included a reproducible example.
I am trying to do some simple operation in one of my matrices. My matrices are 3D arrays which contain capture-recapture data.
Rows are individuals
Columns from 1 to 7 are sampling occasions (years)
Column 8 sex of the individual: 1 males 2 females
libray(abind)
CH <- array(c(1,0,1,1,1,1,0), dim = c(5,7,10))
sex <- c(1,1,2,2,1)
CH_with_sex <- abind(CH, array(sex, replace(dim(CH), 2, 1)), along = 2)
CH_with_sex
, , 1
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 0 0 1 1 1
[2,] 0 0 1 1 1 1 1 1
[3,] 1 1 1 1 0 0 1 2
[4,] 1 0 0 1 1 1 1 2
[5,] 1 1 1 1 1 0 0 1
, , 2
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 0 0 1 1 1
[2,] 0 0 1 1 1 1 1 1
[3,] 1 1 1 1 0 0 1 2
[4,] 1 0 0 1 1 1 1 2
[5,] 1 1 1 1 1 0 0 1
dim(CH_with_sex)
[1] 5 8 10
My aim is to separate males and females from this 3D array and have 2 different arrays: one for the males and another one for females. I thought of making it by filtering for the column 8 but I can't find the way to do it. I end up breaking or losing the matrix structure. Any advice?
My desired output would be this for males:
, , 1
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 0 0 1 1 1
[2,] 0 0 1 1 1 1 1 1
[3,] 1 1 1 1 1 0 0 1
, , 2
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 0 0 1 1 1
[2,] 0 0 1 1 1 1 1 1
[3,] 1 1 1 1 1 0 0 1
And this for females:
, , 1
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 1 0 0 1 2
[2,] 1 0 0 1 1 1 1 2
, , 2
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 1 0 0 1 2
[2,] 1 0 0 1 1 1 1 2
Here, x is your three-dimensional array CH_with_sex, and l is a list of two three-dimensional arrays splitting x by sex.
d <- dim(x)
f <- function(i) x[i, , , drop = FALSE]
l <- c(tapply(seq_len(d[1L]), x[, d[2L], 1L], f, simplify = FALSE))
dim(l[[1]])
## [1] 3 8 10
dim(l[[2]])
## [1] 2 8 10

Find minimum value of two dice roll in R

Instead of using a loop to find a minimum of two dice roll in R such as:
Min <- matrix(0, nrow=6, ncol=6)
d1 <- 1:6
d2 <- 1:6
for(k in 1:6){
for(j in 1:6){
Min[k,j] <- min( c(d1[k], d2[j]) )
}
}
Is there a simpler way or shorter code to get the following result?
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 1 1 1
[2,] 1 2 2 2 2 2
[3,] 1 2 3 3 3 3
[4,] 1 2 3 4 4 4
[5,] 1 2 3 4 5 5
[6,] 1 2 3 4 5 6
outer(d1,d2,pmin)
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 1 1 1
[2,] 1 2 2 2 2 2
[3,] 1 2 3 3 3 3
[4,] 1 2 3 4 4 4
[5,] 1 2 3 4 5 5
[6,] 1 2 3 4 5 6
*apply loops are loops just like for loops but they make nice one-liners.
sapply(1:6, function(y) sapply(1:6, function(x) min(x, y)))
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 1 1 1 1 1 1
#[2,] 1 2 2 2 2 2
#[3,] 1 2 3 3 3 3
#[4,] 1 2 3 4 4 4
#[5,] 1 2 3 4 5 5
#[6,] 1 2 3 4 5 6
#user2974951's answer is way better, but here's my solution anyways:
a <- matrix(0, nrow = 6, ncol = 6)
for (i in 6:1){
a[,i] <- i
a[i,] <- i
}
a
#> [,1] [,2] [,3] [,4] [,5] [,6]
#>[1,] 1 1 1 1 1 1
#>[2,] 1 2 2 2 2 2
#>[3,] 1 2 3 3 3 3
#>[4,] 1 2 3 4 4 4
#>[5,] 1 2 3 4 5 5
#>[6,] 1 2 3 4 5 6

How to select unique columns in an R matrix

I want to select the unique columns in the matrix six on a simulation as follows:
> set.seed(3)
> sam = replicate(100, sample(1:3, 4, rep = T))
> (six = sam[,colSums(sam)==6])
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 2 1 1 1 1 1 1 1 2 1
[2,] 2 2 3 1 1 2 2 1 2 2
[3,] 1 1 1 1 2 1 1 3 1 1
[4,] 1 2 1 3 2 2 2 1 1 2
I would like to end up with a matrix as:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 2 1 1 1 1 1
[2,] 2 2 3 1 1 1
[3,] 1 1 1 1 2 3
[4,] 1 2 1 3 2 1
Use unique function with MARGIN=2 and it will return a matrix with duplicated columns removed, by default, unique removes duplicated rows:
unique(six, MARGIN = 2)
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 2 1 1 1 1 1
#[2,] 2 2 3 1 1 1
#[3,] 1 1 1 1 2 3
#[4,] 1 2 1 3 2 1
We can use duplicated
six[,!duplicated(t(six))]
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 2 1 1 1 1 1
#[2,] 2 2 3 1 1 1
#[3,] 1 1 1 1 2 3
#[4,] 1 2 1 3 2 1

Apply family of functions in R

I have a double loop in this form:
for (j in 1:col(mat))
{
for (i in 1:nrow(mat))
{
decision[i][j] = ifelse(mat[i][j] > 3, 1, 0)
}
}
Is there any way this functionality can be achieved through one of the apply functions with significantly improved speed?
You don't need any loops. If you create a matrix that looks like this
mat<-matrix(sample(1:10, 5*7, replace=T), ncol=7)
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#[1,] 9 6 10 7 6 10 6
#[2,] 7 6 3 3 6 8 3
#[3,] 7 9 7 5 6 7 6
#[4,] 2 3 8 6 10 1 5
#[5,] 4 1 5 6 1 10 6
then you can just do
decision <- (mat>3)+0
decision;
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
#[1,] 1 1 1 1 1 1 1
#[2,] 1 1 0 0 1 1 0
#[3,] 1 1 1 1 1 1 1
#[4,] 0 0 1 1 1 0 1
#[5,] 1 0 1 1 0 1 1
R is a vectorized language, so for this kind of simple manipulation of a matrix apply type functions are not needed, just do:
decision <- ifelse(mat > 3, 1, 0)
(I'm assuming you want to iterate through the elements of the matrix, which means you would say ncol(mat) in your loop; col gives something rather different).

how to bind the same vector multiple times?

How can I bind the same vector o = c(1,2,3,4) multiple times to get a matrix like:
o = array(c(1,2,3,4,1,2,3,4,1,2,3,4), dim(c(4,3))
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 2 2 2
[3,] 3 3 3
[4,] 4 4 4
In a nicer way than: o = cbind(o,o,o) and maybe more generalized (duplicate)? I need this to specify colors for elements in textplot.
R recycles. It's very eco-friendly:
o=c(1,2,3,4)
> matrix(o,nrow = 4,ncol = 4)
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 2 2 2 2
[3,] 3 3 3 3
[4,] 4 4 4 4
You can use replicate
> o = c(1,2,3,4)
> replicate(4, o)
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 2 2 2 2
[3,] 3 3 3 3
[4,] 4 4 4 4
You can use outer
outer(1:4,1:4,function(x,y)x)
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 2 2 2 2
[3,] 3 3 3 3
[4,] 4 4 4 4

Resources