Rank numbers by comparing two matrices - r

Having a matrix A like:
[,1] [,2] [,3] [,4]
[1,] 1 4 7 6
[2,] 2 5 8 1
[3,] 5 1 7 8
and a matrix B like:
[,1]
[1,] 8
[2,] 6
[3,] 1
[4,] 7
[5,] 5
[6,] 2
[7,] 3
[8,] 4
I want to get create a matrix C similar to A replacing A values with the rank of A values in matrix B. The result should be:
matrix C
[,1] [,2] [,3] [,4]
[1,] 3 8 4 2
[2,] 6 5 1 3
[3,] 5 3 4 1

You can use match and adjust the dimensions:
C <- match(A, B)
dim(C) <- dim(A)
--
Example:
> set.seed(123)
> (A <- matrix(sample(1:8), ncol = 4))
[,1] [,2] [,3] [,4]
[1,] 3 8 4 2
[2,] 6 5 1 7
> (B <- matrix(sample(1:8), ncol= 1))
[,1]
[1,] 5
[2,] 4
[3,] 6
[4,] 3
[5,] 8
[6,] 2
[7,] 1
[8,] 7
> (C <- match(A, B))
[1] 4 3 5 1 2 7 6 8
> (dim(C) <- dim(A))
[1] 2 4
> C
[,1] [,2] [,3] [,4]
[1,] 4 5 2 6
[2,] 3 1 7 8

Related

Removing subelements from a list which appear in another subelements list in R

I have two lists of matrix
lst1 <- lapply(1:4, function(i) combn(x=4,m=i))
lst2 <- lapply(1:5, function(i) combn(x=5,m=i))
and would like to extract the columns for matrix in the 2nd list that is not in the columns of matrix in the first list. Can you help please?
e.g.
I would like to get this list below
[[1]]
[,5]
[1,] 5
[[2]]
[,4] [,7] [,9] [,10]
[1,] 1 2 3 4
[2,] 5 5 5 5
[[3]]
[,3] [,5] [,6] [,8] [,9] [,10]
[1,] 1 1 1 2 2 3
[2,] 2 3 4 3 4 4
[3,] 5 5 5 5 5 5
[[4]]
[,2] [,3] [,4] [,5]
[1,] 1 1 1 2
[2,] 2 2 3 3
[3,] 3 4 4 4
[4,] 5 5 5 5
[[5]]
[,1]
[1,] 1
[2,] 2
[3,] 3
[4,] 4
[5,] 5
Here is another base R option
fpaste <- function(x) tapply(x, col(x), toString)
fun1 <- Vectorize(function(x, y) x[,!fpaste(x) %in% fpaste(y), drop = FALSE])
m1 <- outer(lst2, lst1, FUN = fun1)
c(diag(m1), m1[length(m1)])
#[[1]]
# [,1]
#[1,] 5
#[[2]]
# [,1] [,2] [,3] [,4]
#[1,] 1 2 3 4
#[2,] 5 5 5 5
#[[3]]
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 1 1 1 2 2 3
#[2,] 2 3 4 3 4 4
#[3,] 5 5 5 5 5 5
#[[4]]
# [,1] [,2] [,3] [,4]
#[1,] 1 1 1 2
#[2,] 2 2 3 3
#[3,] 3 4 4 4
#[4,] 5 5 5 5
#[[5]]
# [,1]
#[1,] 1
#[2,] 2
#[3,] 3
#[4,] 4
#[5,] 5
How about the following
lapply(lst2, function(x) Filter(Negate(is.null), lapply(lst1, function(y)
if (nrow(x) == nrow(y)) x[, !apply(x, 2, toString) %in% apply(y, 2, toString)])))
#[[1]]
#[[1]][[1]]
#[1] 5
#
#
#[[2]]
#[[2]][[1]]
# [,1] [,2] [,3] [,4]
#[1,] 1 2 3 4
#[2,] 5 5 5 5
#
#
#[[3]]
#[[3]][[1]]
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 1 1 1 2 2 3
#[2,] 2 3 4 3 4 4
#[3,] 5 5 5 5 5 5
#
#
#[[4]]
#[[4]][[1]]
# [,1] [,2] [,3] [,4]
#[1,] 1 1 1 2
#[2,] 2 2 3 3
#[3,] 3 4 4 4
#[4,] 5 5 5 5
#
#
#[[5]]
#list()
For every entry in lst2 we check for unique columns from all entries in lst1. Therefore the length of the output list equals the length of lst2, which makes it easy to identify entries from lst2 that have no unique columns with any entry from lst1 (as is the case for the fifth entry from lst2).
Update
To exactly reproduce your expected output you can do
lst <- lapply(lst2, function(x) Filter(Negate(is.null), lapply(lst1, function(y)
if (nrow(x) == nrow(y)) x[, !apply(x, 2, toString) %in% apply(y, 2, toString)])))
lst <- unlist(lapply(seq_along(lst), function(i)
if (length(lst[[i]]) == 0) lst[[i]] <- list(lst2[[i]]) else lst[[i]]), recursive = F)
lst;
#[[1]]
#[1] 5
#
#[[2]]
# [,1] [,2] [,3] [,4]
#[1,] 1 2 3 4
#[2,] 5 5 5 5
#
#[[3]]
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 1 1 1 2 2 3
#[2,] 2 3 4 3 4 4
#[3,] 5 5 5 5 5 5
#
#[[4]]
# [,1] [,2] [,3] [,4]
#[1,] 1 1 1 2
#[2,] 2 2 3 3
#[3,] 3 4 4 4
#[4,] 5 5 5 5
#
#[[5]]
# [,1]
#[1,] 1
#[2,] 2
#[3,] 3
#[4,] 4
#[5,] 5
Using Base R:
Map(function(x,y)as.matrix(unname(setdiff(data.frame(y),data.frame(x)))),c(lst1,NA),lst2)
[[1]]
[,1]
1 5
[[2]]
[,1] [,2] [,3] [,4]
1 1 2 3 4
2 5 5 5 5
[[3]]
[,1] [,2] [,3] [,4] [,5] [,6]
1 1 1 1 2 2 3
2 2 3 4 3 4 4
3 5 5 5 5 5 5
[[4]]
[,1] [,2] [,3] [,4]
1 1 1 1 2
2 2 2 3 3
3 3 4 4 4
4 5 5 5 5
[[5]]
[,1]
1 1
2 2
3 3
4 4
5 5
or you can do
purrr::map2(c(lst1,NA),lst2,~as.matrix(unname(setdiff(data.frame(.y),data.frame(.x)))))
[[1]]
[,1]
[1,] 5
[[2]]
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 5 5 5
[[3]]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 1 2 2 3
[2,] 2 3 4 3 4 4
[3,] 5 5 5 5 5 5
[[4]]
[,1] [,2] [,3] [,4]
[1,] 1 1 1 2
[2,] 2 2 3 3
[3,] 3 4 4 4
[4,] 5 5 5 5
[[5]]
[,1]
[1,] 1
[2,] 2
[3,] 3
[4,] 4
[5,] 5
This should work:
foo <- function(z,w) w[,!apply(matrix(apply(w,2,function(y) apply(z, 2,
function(x) identical(x, y))), nrow=ncol(z)),2,any)]
mapply(foo, lst1,lst2)

Concatenate each row of a matrix with each element of another matrix R

I want to concatenate each row of a matrix (say m1) with each element of another matrix (m2). Here follows an exmple:
m1 <- t(combn(4,2))
m2 <- matrix(NA,nrow(m1),2)
for(i in 1:nrow(m1)){
m2[i,] <- seq(1,4,1)[-c(m1[i,])]
}
> m1
[,1] [,2]
[1,] 1 2
[2,] 1 3
[3,] 1 4
[4,] 2 3
[5,] 2 4
[6,] 3 4
> m2
[,1] [,2]
[1,] 3 4
[2,] 2 4
[3,] 2 3
[4,] 1 4
[5,] 1 3
[6,] 1 2
The matrix that I want should be like this:
> m3
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 1 2 4
[3,] 1 3 2
[4,] 1 3 4
[5,] 1 4 2
[6,] 1 4 3
[7,] 2 3 1
[8,] 2 3 4
[9,] 2 4 1
[10,] 2 4 3
[11,] 3 4 1
[12,] 3 4 2
What is the best practice in this case?
As per the expected output, the logic seems to be that we are expanding the rows of the first dataset by also includng the second dataset, so the number of rows should be double as of the first. In the current approach, we used rep to expand the rows and then cbind with the vector created from the second matrix
cbind(m1[rep(1:nrow(m1), each = 2),], c(t(m2)))
# [,1] [,2] [,3]
# [1,] 1 2 3
# [2,] 1 2 4
# [3,] 1 3 2
# [4,] 1 3 4
# [5,] 1 4 2
# [6,] 1 4 3
# [7,] 2 3 1
# [8,] 2 3 4
# [9,] 2 4 1
#[10,] 2 4 3
#[11,] 3 4 1
#[12,] 3 4 2

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

R matlab package: why is repmat inconsistent?

I have got a question regarding the matlab package for R. Here's what I get
library(matlab)
a = matrix(1:4,2,2)
repmat(a,3,1)
[,1] [,2]
[1,] 1 2
[2,] 3 4
[3,] 1 2
[4,] 3 4
[5,] 1 2
[6,] 3 4
this is what I expect. replicate a three times along the first dimension. but
b = matrix(1:6,2,3)
b
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
repmat(b,3,1)
[,1] [,2]
[1,] 1 2
[2,] 3 4
[3,] 5 6
[4,] 1 2
[5,] 3 4
[6,] 5 6
[7,] 1 2
[8,] 3 4
[9,] 5 6
this is not consistent. I want a 6 by 3 matrix as the one obtained by
rbind(b,rbind(b,b))
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
[3,] 1 3 5
[4,] 2 4 6
[5,] 1 3 5
[6,] 2 4 6
It just appears to be transposing the matrix before doing the stacking. You could just transpose your matrix before sending it into repmat
> repmat(t(b), 3, 1)
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
[3,] 1 3 5
[4,] 2 4 6
[5,] 1 3 5
[6,] 2 4 6

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