Duplicate matrix to form list - r

a is a matrix.
a<-matrix(c(2,2,1,1,1,2,1,2,1,1,2,1,1,1,1,1,1,2,2,2,1,2,1,1),6)
I want to duplicate matrix "a" 3 times to form a list.
I have tried:
as.list(rep(a,3))
but it doesn't work.
My expected result is as follows:
[[1]]
[,1] [,2] [,3] [,4]
[1,] 2 1 1 2
[2,] 2 2 1 2
[3,] 1 1 1 1
[4,] 1 1 1 2
[5,] 1 2 1 1
[6,] 2 1 2 1
[[2]]
[,1] [,2] [,3] [,4]
[1,] 2 1 1 2
[2,] 2 2 1 2
[3,] 1 1 1 1
[4,] 1 1 1 2
[5,] 1 2 1 1
[6,] 2 1 2 1
[[3]]
[,1] [,2] [,3] [,4]
[1,] 2 1 1 2
[2,] 2 2 1 2
[3,] 1 1 1 1
[4,] 1 1 1 2
[5,] 1 2 1 1
[6,] 2 1 2 1

rep returns the same type it receives, so if you pass it a numeric matrix, it's going to try to return a numeric vector of some sort–not a list. The solution, though, is simple: if you want a list, pass it a list:
rep(list(a), 3)
# [[1]]
# [,1] [,2] [,3] [,4]
# [1,] 2 1 1 2
# [2,] 2 2 1 2
# [3,] 1 1 1 1
# [4,] 1 1 1 2
# [5,] 1 2 1 1
# [6,] 2 1 2 1
#
# [[2]]
# [,1] [,2] [,3] [,4]
# [1,] 2 1 1 2
# [2,] 2 2 1 2
# [3,] 1 1 1 1
# [4,] 1 1 1 2
# [5,] 1 2 1 1
# [6,] 2 1 2 1
#
# [[3]]
# [,1] [,2] [,3] [,4]
# [1,] 2 1 1 2
# [2,] 2 2 1 2
# [3,] 1 1 1 1
# [4,] 1 1 1 2
# [5,] 1 2 1 1
# [6,] 2 1 2 1

Maybe using lapply:
lapply(1:3, function(i) a)
Benchmarking:
library(microbenchmark)
a <- matrix(c(2,2,1,1,1,2,1,2,1,1,2,1,1,1,1,1,1,2,2,2,1,2,1,1),6)
microbenchmark(
replicate(3, a, simplify = FALSE),
rep(list(a), 3),
lapply(1:3, function(i) a),
times = 10000)
# Unit: nanoseconds
# expr min lq mean median uq max neval cld
# replicate(3, a, simplify = FALSE) 5987 7127 8044.9371 7413 7983 1150921 10000 c
# rep(list(a), 3) 0 285 396.2066 285 570 15395 10000 a
# lapply(1:3, function(i) a) 1995 2566 3013.6994 2851 3136 1290902 10000 b

Related

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

Get index locations of 0s which are completely surrounded by 1s

I have a matrix like so:
m <- matrix(c(1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,2,0,1,1,1,1,1,1,1,1,1), nrow = 12, ncol = 12)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 1 1 1 1 1 1 1 1 1 1 1 1
[2,] 1 1 2 1 1 2 1 1 2 1 1 2
[3,] 1 1 0 1 1 0 1 1 0 1 1 0
[4,] 1 1 1 1 1 1 1 1 1 1 1 1
[5,] 1 1 1 1 1 1 1 1 1 1 1 1
[6,] 1 1 1 1 1 1 1 1 1 1 1 1
[7,] 1 1 1 1 1 1 1 1 1 1 1 1
[8,] 1 1 1 1 1 1 1 1 1 1 1 1
[9,] 0 1 1 0 1 1 0 1 1 0 1 1
[10,] 1 1 1 1 1 1 1 1 1 1 1 1
[11,] 1 1 1 1 1 1 1 1 1 1 1 1
[12,] 1 1 1 1 1 1 1 1 1 1 1 1
and I want to find the index locations where 0 is completely surrounded by 1s in a 3x3 window. I can find all the zeros with:
which(m == 0) but this will also return places where a 2 surrounds a 0 such as at index location m[3,3]
w <- which(m == 0, arr.ind = TRUE)
w
# row col
# [1,] 9 1
# [2,] 3 3
# [3,] 9 4
# [4,] 3 6
# [5,] 9 7
# [6,] 3 9
# [7,] 9 10
# [8,] 3 12
We don't need to know which zeroes are on a boundary, so filter out those:
w <- w[ w[,1] > 1 & w[,1] < (nrow(m)-1) & w[,2] > 2 & w[,2] < (ncol(m)-1), ]
w
# row col
# [1,] 3 3
# [2,] 9 4
# [3,] 3 6
# [4,] 9 7
# [5,] 3 9
# [6,] 9 10
Now we can take those inner indices and build 3x3 submatrices into a list. Here are the first couple (of six):
Map(function(rn,cn) m[rn+(-1:1),cn+(-1:1)], w[,1], w[,2])[1:2]
# [[1]]
# [,1] [,2] [,3]
# [1,] 1 2 1
# [2,] 1 0 1
# [3,] 1 1 1
# [[2]]
# [,1] [,2] [,3]
# [1,] 1 1 1
# [2,] 1 0 1
# [3,] 1 1 1
Now we can just filter out the ones where there is only one non-1 entry in the matrix.
Filter(function(m3) sum(m3 != 1) == 1, Map(function(rn,cn) m[rn+(-1:1),cn+(-1:1)], w[,1], w[,2]))
# [[1]]
# [,1] [,2] [,3]
# [1,] 1 1 1
# [2,] 1 0 1
# [3,] 1 1 1
# [[2]]
# [,1] [,2] [,3]
# [1,] 1 1 1
# [2,] 1 0 1
# [3,] 1 1 1
# [[3]]
# [,1] [,2] [,3]
# [1,] 1 1 1
# [2,] 1 0 1
# [3,] 1 1 1
Since you need to just count the occurrences, add length(...) around that, and you have your answer.
(If you're curious, the reason I went with sum(m3!=1)==1 is because I wasn't certain if you wanted the border submatrices as well. If you wanted those, then the number of 1s would be reduced, not "8" as a typical 3x3 would be. But we know that there should always be exactly one non-1 in the submatrix: the center 0.)
To get just the indices that match,
w[mapply(function(rn,cn) sum(m[rn+(-1:1),cn+(-1:1)] != 1) == 1,
w[,1], w[,2]),]
# row col
# [1,] 9 4
# [2,] 9 7
# [3,] 9 10

Matrix indices ordered by the value they contain

I have a matrix like this:
mat<-matrix(c(10,45,2,15,3,98,1,7,13),nrow = 3)
mat
[,1] [,2] [,3]
[1,] 10 15 1
[2,] 45 3 7
[3,] 2 98 13
I want to get the indices of ordered values, as what we can get from order(x, arr.idx = T) but applied to a matrix. That is:
[,1] [,2]
1 3
3 1
2 2
2 3
1 1
3 3
1 2
2 1
3 2
Is it there a fast way to do it?
Thank you in advance
You can use
arrayInd(order(mat), dim(mat), dimnames(mat))
# [,1] [,2]
# [1,] 1 3
# [2,] 3 1
# [3,] 2 2
# [4,] 2 3
# [5,] 1 1
# [6,] 3 3
# [7,] 1 2
# [8,] 2 1
# [9,] 3 2
Using the order as index, we rearrange the row and col of 'mat' and cbind it to get the row/column index of the ordered values
i1 <- order(mat)
cbind(row(mat)[i1], col(mat)[i1])
# [,1] [,2]
#[1,] 1 3
#[2,] 3 1
#[3,] 2 2
#[4,] 2 3
#[5,] 1 1
#[6,] 3 3
#[7,] 1 2
#[8,] 2 1
#[9,] 3 2

Creating a matrix of multiple counters in R

So, my goal is to take an input vector and to make an output matrix of different counters. So every time a value appears in my inputs, I want to find that counter and iterate it by 1. I understand that I'm not good at explaining this, so I illustrated a simple version below. However, I want to make 2 changes which I will enumerate after the example so that it makes sense.
nums = c(1,2,3,4,5,1,2,4,3,5)
unis = unique(nums)
counter = matrix(NA, nrow = length(nums), ncol = length(unis))
colnames(counter) = unis
for (i in 1:length(nums)){
temp = nums[i]
if (i == 1){
counter[1,] = 0
counter[1,temp] = 1
} else {
counter[i,] = counter[i-1,]
counter[i,temp] = counter[i-1,temp]+1
}
}
counter
which outputs
> counter
1 2 3 4 5
[1,] 1 0 0 0 0
[2,] 1 1 0 0 0
[3,] 1 1 1 0 0
[4,] 1 1 1 1 0
[5,] 1 1 1 1 1
[6,] 2 1 1 1 1
[7,] 2 2 1 1 1
[8,] 2 2 1 2 1
[9,] 2 2 2 2 1
[10,] 2 2 2 2 2
The 2 modifications. 1) Since the real data is much larger, I would want to do this using apply or however people who know R better than me says it should be done. 2) Whereas the input is a vector where each element is only an element, how could this be generalized if an element of a vector was a tuple? For example (if nums was a tuple of 4 and 5, then it would iterate both in that step and the last line of the output would then be 2,2,2,3,2)
Thanks and if you don't understand please ask questions and I'll try to clarify
Using the Matrix package (which ships with a standard installation of R)
nums <- c(1,2,3,4,5,1,2,4,3,5)
apply(Matrix::sparseMatrix(i=seq_along(nums), j=nums), 2, cumsum)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 0 0 0 0
# [2,] 1 1 0 0 0
# [3,] 1 1 1 0 0
# [4,] 1 1 1 1 0
# [5,] 1 1 1 1 1
# [7,] 2 2 1 1 1
# [8,] 2 2 1 2 1
# [9,] 2 2 2 2 1
# [10,] 2 2 2 2 2
Note that this behaves a bit differently in a couple of ways from thelatemail's suggested solution. Which behavior you prefer will depend on what you are using this for.
Here's a small example that illustrates the differences:
nums <- c(5,2,1,1)
# My suggestion
apply(Matrix::sparseMatrix(i=seq_along(nums), j=nums), 2, cumsum)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 0 0 0 0 1
# [2,] 0 1 0 0 1
# [3,] 1 1 0 0 1
# [4,] 2 1 0 0 1
# #thelatemail's suggestion
sapply(unique(nums), function(x) cumsum(nums==x) )
# [,1] [,2] [,3]
# [1,] 1 0 0
# [2,] 1 1 0
# [3,] 1 1 1
# [4,] 1 1 2
For your second question, you could do something like this:
nums <- list(1,2,3,4,5,1,2,4,3,c(4,5))
ii <- rep(seq_along(nums), times=lengths(nums)) ## lengths() is in R>=3.2.0
jj <- unlist(nums)
apply(Matrix::sparseMatrix(i=ii, j=jj), 2, cumsum)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 0 0 0 0
# [2,] 1 1 0 0 0
# [3,] 1 1 1 0 0
# [4,] 1 1 1 1 0
# [5,] 1 1 1 1 1
# [6,] 2 1 1 1 1
# [7,] 2 2 1 1 1
# [8,] 2 2 1 2 1
# [9,] 2 2 2 2 1
# [10,] 2 2 2 3 2
For your first query, you can get there with something like:
sapply(unique(nums), function(x) cumsum(nums==x) )
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 0 0 0 0
# [2,] 1 1 0 0 0
# [3,] 1 1 1 0 0
# [4,] 1 1 1 1 0
# [5,] 1 1 1 1 1
# [6,] 2 1 1 1 1
# [7,] 2 2 1 1 1
# [8,] 2 2 1 2 1
# [9,] 2 2 2 2 1
#[10,] 2 2 2 2 2
Another idea:
do.call(rbind, Reduce("+", lapply(nums, tabulate, max(unlist(nums))), accumulate = TRUE))
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 0 0 0 0
# [2,] 1 1 0 0 0
# [3,] 1 1 1 0 0
# [4,] 1 1 1 1 0
# [5,] 1 1 1 1 1
# [6,] 2 1 1 1 1
# [7,] 2 2 1 1 1
# [8,] 2 2 1 2 1
# [9,] 2 2 2 2 1
#[10,] 2 2 2 2 2
And generally:
x = list(1, 3, 6, c(6, 3), 2, c(4, 6, 1), c(1, 2), 3)
do.call(rbind, Reduce("+", lapply(x, tabulate, max(unlist(x))), accumulate = TRUE))
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 1 0 0 0 0 0
#[2,] 1 0 1 0 0 0
#[3,] 1 0 1 0 0 1
#[4,] 1 0 2 0 0 2
#[5,] 1 1 2 0 0 2
#[6,] 2 1 2 1 0 3
#[7,] 3 2 2 1 0 3
#[8,] 3 2 3 1 0 3

Partitioned matrices in R

I’m looking for a code to create matrix B from matrix A, this is a very simple example my real matrix A is (500 x500) and B11(50x50)
1 2 = A
3 4
1 1 | 2 2
1 1 | 2 2
.----------= B
3 3 | 4 4
3 3 | 4 4
Thanks in advance.
You want a Kronecker product, which is %x%:
R>A <- matrix(1:4,2,2)
R>A
[,1] [,2]
[1,] 1 3
[2,] 2 4
R>X <- matrix(1,2,2)
R>X
[,1] [,2]
[1,] 1 1
[2,] 1 1
R>A %x% X
[,1] [,2] [,3] [,4]
[1,] 1 1 3 3
[2,] 1 1 3 3
[3,] 2 2 4 4
[4,] 2 2 4 4
R>t(A) %x% X
[,1] [,2] [,3] [,4]
[1,] 1 1 2 2
[2,] 1 1 2 2
[3,] 3 3 4 4
[4,] 3 3 4 4

Resources