R: Matrix sorting by only part of a column - r

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

Related

R: how to double the entries in each row of a matrix and insert new rows

mylist <- list(matrix(c(1, 3, -1, 0, 2, 1), nrow = 2, byrow = TRUE),
matrix(c(-2, 0, 10, 1, 2, 9, 2, 0, 0), nrow = 3, byrow = TRUE))
> mylist
[[1]]
[,1] [,2] [,3]
[1,] 1 3 -1
[2,] 0 2 1
[[2]]
[,1] [,2] [,3]
[1,] -2 0 10
[2,] 1 2 9
[3,] 2 0 0
I have a list of matrices called mylist where the dimensions of the matrices can differ. For each matrix, I want to double the row values and insert it as a new row underneath. My desired output is as follows:
[[1]]
[,1] [,2] [,3]
[1,] 1 3 -1
[2,] 2 6 -2
[3,] 0 2 1
[4,] 0 4 2
[[2]]
[,1] [,2] [,3]
[1,] -2 0 10
[2,] -4 0 20
[3,] 1 2 9
[4,] 2 4 18
[5,] 2 0 0
[6,] 4 0 0
In an lapply repeat each row index found using seq_len with nrow and multiply repeatedly by 1:2 exploiting recycling.
lapply(mylist, \(x) x[rep(seq_len(nrow(x)), each=2), ]*1:2)
# [[1]]
# [,1] [,2] [,3]
# [1,] 1 3 -1
# [2,] 2 6 -2
# [3,] 0 2 1
# [4,] 0 4 2
#
# [[2]]
# [,1] [,2] [,3]
# [1,] -2 0 10
# [2,] -4 0 20
# [3,] 1 2 9
# [4,] 2 4 18
# [5,] 2 0 0
# [6,] 4 0 0
You can use rbind but you need to permute rows to get multiplied row beneath:
lapply(
mylist,
function(x){
rbind(x, x * 2)[as.vector(t(matrix(seq_len(nrow(x) * 2), ncol = 2))),]
}
)
[[1]]
[,1] [,2] [,3]
[1,] 1 3 -1
[2,] 2 6 -2
[3,] 0 2 1
[4,] 0 4 2
[[2]]
[,1] [,2] [,3]
[1,] -2 0 10
[2,] -4 0 20
[3,] 1 2 9
[4,] 2 4 18
[5,] 2 0 0
[6,] 4 0 0
Another base R approach which also utilises the rbind function with do.call.
lapply(mylist, function(x)
do.call(rbind, lapply(1:nrow(x), function(i) rbind(x[i, ], x[i,]*2))))
[[1]]
[,1] [,2] [,3]
[1,] 1 3 -1
[2,] 2 6 -2
[3,] 0 2 1
[4,] 0 4 2
[[2]]
[,1] [,2] [,3]
[1,] -2 0 10
[2,] -4 0 20
[3,] 1 2 9
[4,] 2 4 18
[5,] 2 0 0
[6,] 4 0 0

Transform Identity Matrix

I have identity matrix which can be generated via diag(5)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 0 1 0 0 0
[3,] 0 0 1 0 0
[4,] 0 0 0 1 0
[5,] 0 0 0 0 1
I want to convert it to the matrix wherein series starts after 1. For example 1st column, values 1 through 5. Second column - values 1 through 4.
Desired Output
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 2 1 0 0 0
[3,] 3 2 1 0 0
[4,] 4 3 2 1 0
[5,] 5 4 3 2 1
Try the code below (given m <- diag(5))
> (row(m) - col(m) + 1)*lower.tri(m,diag = TRUE)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 2 1 0 0 0
[3,] 3 2 1 0 0
[4,] 4 3 2 1 0
[5,] 5 4 3 2 1
Another option is using apply + cumsum
> apply(lower.tri(m, diag = TRUE), 2, cumsum)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 2 1 0 0 0
[3,] 3 2 1 0 0
[4,] 4 3 2 1 0
[5,] 5 4 3 2 1
1) If d <- diag(5) is the identity matrix then:
pmax(row(d) - col(d) + 1, 0)
giving:
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 2 1 0 0 0
[3,] 3 2 1 0 0
[4,] 4 3 2 1 0
[5,] 5 4 3 2 1
2) This alternative is slightly longer (though still a one-liner) but also works if the columns of d are rearranged and/or some columns are missing. For example,
dd <- d[, 4:1] # test data
pmax(outer(1:nrow(dd) + 1, max.col(t(dd)), `-`), 0)
giving the same result for d and this for dd:
[,1] [,2] [,3] [,4]
[1,] 0 0 0 1
[2,] 0 0 1 2
[3,] 0 1 2 3
[4,] 1 2 3 4
[5,] 2 3 4 5
A solution based on nested cumsum:
n <- 5
m <- diag(n)
apply(m, 2, function(x) cumsum(cumsum(x)))
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 1 0 0 0 0
#> [2,] 2 1 0 0 0
#> [3,] 3 2 1 0 0
#> [4,] 4 3 2 1 0
#> [5,] 5 4 3 2 1
One option could be:
x <- 1:5
embed(c(rep(0, length(x) - 1), x), length(x))
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 2 1 0 0 0
[3,] 3 2 1 0 0
[4,] 4 3 2 1 0
[5,] 5 4 3 2 1

Two-circulant matrix in R

How to construct a two-circulant matrix?
For example, the following matrix A is two-circulant, i.e every column (expect from the first one) is obtained from the previous one by putting the last two elements as first. Note that the first column is the generator of the matrix.
N=12
k=6
x=c(0,0,0,0,1,1,1,1,2,2,2,2)
A=matrix(0,N,k)
A[,1]=x
for( j in 2:ncol(A) )
{
A[,j]=c(A[11:12,j-1],A[1:10,j-1])
}
> A
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0 2 2 1 1 0
[2,] 0 2 2 1 1 0
[3,] 0 0 2 2 1 1
[4,] 0 0 2 2 1 1
[5,] 1 0 0 2 2 1
[6,] 1 0 0 2 2 1
[7,] 1 1 0 0 2 2
[8,] 1 1 0 0 2 2
[9,] 2 1 1 0 0 2
[10,] 2 1 1 0 0 2
[11,] 2 2 1 1 0 0
[12,] 2 2 1 1 0 0
Is there any other way to constuct the matrix A? For example by using a function.
You could use the following:
circular_matrix <- function(x, ncol) {
coll <- list(x)
for (i in 1:(ncol-1)) {
current <- coll[[length(coll)]]
coll[[length(coll) + 1]] <- c(tail(current, 2), current[1:(length(current) - 2)])
}
do.call(cbind, coll)
}
circular_matrix(1:10, 5)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 9 7 5 3
# [2,] 2 10 8 6 4
# [3,] 3 1 9 7 5
# [4,] 4 2 10 8 6
# [5,] 5 3 1 9 7
# [6,] 6 4 2 10 8
# [7,] 7 5 3 1 9
# [8,] 8 6 4 2 10
# [9,] 9 7 5 3 1
#[10,] 10 8 6 4 2

How to generate a matrix of difference of two vectors in R

I have two vectors and I want to get a matrix of differences:
a = 1:4
b = 1:4
[,1] [,2] [,3] [,4]
[1,] 0 1 2 3
[2,] -1 0 1 2
[3,] -2 -1 0 1
[4,] -3 -2 -1 0
How can this be done? Thanks!
-outer(1:4, 1:4, '-')
## [,1] [,2] [,3] [,4]
## [1,] 0 1 2 3
## [2,] -1 0 1 2
## [3,] -2 -1 0 1
## [4,] -3 -2 -1 0

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