How to select unique columns in an R matrix - r

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

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

R: Matrix sorting by only part of a column

I have a matrix, say:
c <- c(1,2,3,4,5,0,1,-5,3,1,-3,2,-2,1,2,0,1,0,3,3,5,-5,3,-1,0)
M <- matrix(c, byrow=T, nrow=5)
M
So:
M
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 0 1 -5 3 1
[3,] -3 2 -2 1 2
[4,] 0 1 0 3 3
[5,] 5 -5 3 -1 0
I know how to sort M by absolute values of column [,3] (for example):
Ma <- abs(M)
Ms <- M[order(Ma[,3], decreasing = T),]
Ms
So:
Ms
[,1] [,2] [,3] [,4] [,5]
[1,] 0 1 -5 3 1
[2,] 1 2 3 4 5
[3,] 5 -5 3 -1 0
[4,] -3 2 -2 1 2
[5,] 0 1 0 3 3
But what I would like to have is M sorted not by the entire column [,3], but only by the last 3 absolute values, so that the first two lines of M are not changed:
Ms
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 0 1 -5 3 1
[3,] 5 -5 3 -1 0
[4,] -3 2 -2 1 2
[5,] 0 1 0 3 3
I couldn't find how to do this in a simple way. Any idea ?
Thanks.
We can try
M[(nrow(M)-2):nrow(M),] <- tail(M,3)[order(tail(Ma[,3],3), decreasing=TRUE),]
M
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 2 3 4 5
#[2,] 0 1 -5 3 1
#[3,] 5 -5 3 -1 0
#[4,] -3 2 -2 1 2
#[5,] 0 1 0 3 3
M[c(1:2,2L+order(abs(M[-1:-2,3L]),decreasing=T)),];
## [,1] [,2] [,3] [,4] [,5]
## [1,] 1 2 3 4 5
## [2,] 0 1 -5 3 1
## [3,] 5 -5 3 -1 0
## [4,] -3 2 -2 1 2
## [5,] 0 1 0 3 3

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

apply function to elements over a list

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]]))

Resources