I have a set of vectors, and would like to stack them on top of each other to create diagonal entries to a matrix.
What would be an easy way to create the example_out matrix from c1 and c2?
c1 <- seq(1, 4)
c2 <- seq(5, 8)
example_out <- matrix(c(1,0,0,0,5,2,0,0,0,6,3,0,0,0,7,4,0,0,0,8), nrow=5, byrow=T)
example_out
Create a matrix out of 0s, then fill main diagonal with c1 and sub diagonal with c2.
example_out <- matrix(rep(0, 20), 5, 4)
diag(example_out) <- c1
diag(example_out[-1, ]) <- c2
Yielding
> example_out
[,1] [,2] [,3] [,4]
[1,] 1 0 0 0
[2,] 5 2 0 0
[3,] 0 6 3 0
[4,] 0 0 7 4
[5,] 0 0 0 8
Data
c1 <- seq(1, 4)
c2 <- seq(5, 8)
Another simple approach, augmenting two diagonal matrices with 0 rows and adding them:
rbind(diag(c1), 0) + rbind(0, diag(c2))
# [,1] [,2] [,3] [,4]
# [1,] 1 0 0 0
# [2,] 5 2 0 0
# [3,] 0 6 3 0
# [4,] 0 0 7 4
# [5,] 0 0 0 8
Here is an alternative approach replaceing entries in a numeric vector before casting as matrix
matrix(unlist(sapply(seq_along(c1), function(i)
replace(rep(0, length(c1) + 1), i:(i+1), c(c1[i], c2[i])))),
ncol = length(c1))
# [,1] [,2] [,3] [,4]
#[1,] 1 0 0 0
#[2,] 5 2 0 0
#[3,] 0 6 3 0
#[4,] 0 0 7 4
#[5,] 0 0 0 8
Update
I was curious to see how the different methods compared in terms of performance/runtime. Here is a short microbenchmark analysis using two larger vectors c1 and c2.
set.seed(2017)
c1 <- sample(1000)
c2 <- sample(1000)
library(microbenchmark)
library(Matrix)
res <- microbenchmark(
method_jaySF = {
example_out <- matrix(0, length(c1) + 1, length(c2))
diag(example_out) <- c1
diag(example_out[-1, ]) <- c2
},
method_Roland = {
bandSparse(length(c1) + 1, length(c2), 0:-1, list(c1, c2))
},
method_Onyambu = {
a = matrix(0,length(c1)+1,length(c2))
a[row(a)==col(a)]=c1
a[row(a)==col(a)+1]=c2
},
method_Gregor = {
rbind(diag(c1), 0) + rbind(0, diag(c2))
},
method_Maurits = {
matrix(unlist(sapply(seq_along(c1), function(i)
replace(rep(0, length(c1) + 1), i:(i+1), c(c1[i], c2[i])))),
ncol = length(c1))
}
)
res;
#Unit: microseconds
# expr min lq mean median uq max
# method_jaySF 31894.439 37850.81 58452.41 40560.992 46224.579 208862.631
# method_Roland 940.535 1342.32 1675.29 1457.928 1869.621 8228.287
# method_Onyambu 55033.797 66083.67 124364.44 73143.798 195886.534 274383.132
# method_Gregor 37784.977 44049.87 69918.85 47539.793 53122.162 243774.715
# method_Maurits 14961.924 21378.77 42834.89 23536.966 27270.953 186088.146
autoplot(res)
You should create a sparse matrix. Use the Matrix package:
c1 <- seq(1, 4)
c2 <- seq(5, 8)
library(Matrix)
bandSparse(5, 4, 0:-1, list(c1, c2))
#5 x 4 sparse Matrix of class "dgCMatrix"
#
#[1,] 1 . . .
#[2,] 5 2 . .
#[3,] . 6 3 .
#[4,] . . 7 4
#[5,] . . . 8
a = matrix(0,length(c1)+1,length(c2))
a[row(a)==col(a)]=c1
a[row(a)==col(a)+1]=c2
a
[,1] [,2] [,3] [,4]
[1,] 1 0 0 0
[2,] 5 2 0 0
[3,] 0 6 3 0
[4,] 0 0 7 4
[5,] 0 0 0 8
Related
How do I make a matrix with the sequence 1:16, where all values except 2,3,6,9 and 16 are equal to 0?
I've tried a bunch of different things.
You could do this:
m1 <- 1:16
m2 <- rep(0, 16)
indices <- c(2,3,6,9,16)
m2[indices] <- m1[indices]
matrix(m2, nrow = 4, byrow = TRUE)
# [,1] [,2] [,3] [,4]
# [1,] 0 2 3 0
# [2,] 0 6 0 0
# [3,] 9 0 0 0
# [4,] 0 0 0 16
Depends if the values you want to be non-zero are always going to be at their indices when the matrix is created by row.
You can generalise this method into a function:
create_matrix <- function(max_val, nrow, non_zero_indices) {
m1 <- 1:max_val
m2 <- rep(0, max_val)
m2[non_zero_indices] <- m1[non_zero_indices]
matrix(m2, nrow = nrow, byrow = TRUE)
}
create_matrix(16,4, c(2,3,6,9,16))
# [,1] [,2] [,3] [,4]
# [1,] 0 2 3 0
# [2,] 0 6 0 0
# [3,] 9 0 0 0
# [4,] 0 0 0 16
#akrun's suggestion in the comments will also work if you add byrow=TRUE, so it looks like:
matrix(replace(1:16, !1:16 %in% c(2, 3, 6, 9, 16), 0), 4, 4, byrow=TRUE)
It's a matter of taste.
EDIT: Generation of indices
No one asked for this but I noticed that your indices follow a sequence - specifically they are OEIS A081660 + 1. So instead of typing them directly you could generate them with:
get_indices <- function(n) {
2^(n+1)/3+n+(-1)^n/3 + 1
}
get_indices(0:4)
# [1] 2 3 6 9 16
I have a list of locations and their weights (calculated distances apart) in a matrix.
I would like the optimal solution for each location having 3 connections, minimizing total distance.
costs6 <- matrix(c(0,399671,1525211,990914,1689886,1536081,399671,0,1802419,1128519,1964930,1603803,1525211,1802419,0,814942,164677,943489,990914,1128519.4,814942.7,0,953202,565712,1689886,1964930,164677,953202,0, 1004916,1536081,1603803,943489,565712,1004916,0),ncol=6,byrow=TRUE)
plantcap <- rep(3,6)
citydemand <- rep(3,6)
plant.signs <- rep("=",6)
city.signs <- rep("=",6)
lptrans <- lp.transport(costs6,"min",plant.signs,plantcap,city.signs,citydemand)
lptrans$solution
lptrans
This LP solver returns
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 3 0 0 0 0 0
[2,] 0 3 0 0 0 0
[3,] 0 0 3 0 0 0
[4,] 0 0 0 3 0 0
[5,] 0 0 0 0 3 0
[6,] 0 0 0 0 0 3
I am wondering if there is a way to max out any Xij at 1, so that the solver will give me three ones in each column/row, rather than one 3 in each column/row? If not, is there another solver I can use to find the solution?
Something like this, setting it up as an LP problem (assuming a symmetric solution matrix)?
library(lpSolve)
costs6 <- matrix(c(0,399671,1525211,990914,1689886,1536081,
399671,0,1802419,1128519,1964930,1603803,
1525211,1802419,0,814942,164677,943489,
990914,1128519.4,814942.7,0,953202,565712,
1689886,1964930,164677,953202,0, 1004916,
1536081,1603803,943489,565712,1004916,0),ncol=6,byrow=TRUE)
nLoc <- nrow(costs6)
nParams <- sum(1:(nLoc - 1L))
# set up the constraint matrix
# columns are parameters corresponding to the lower triangular of costs6 (by column)
# the first six constraints are for the row/column sums
# the last 15 constraints are for the maximum number of times each path can be used (1)
nConst <- sum(1:nLoc)
mConst <- matrix(0L, nConst, nParams)
mConst[matrix(c(c(combn(1:nLoc, 2)), rep(1:nParams, each = 2)), ncol = 2)] <- 1L
mConst[(nLoc + 1L):nConst,] <- diag(nParams)
lpSol <- lp(
direction = "min",
objective.in = unlist(costs6[lower.tri(costs6)]),
const.mat = mConst,
const.dir = c(rep("=", nLoc), rep("<=", nParams)),
const.rhs = c(rep(3L, nLoc), rep(1L, nParams)),
all.int = TRUE
)
lpSol
#> Success: the objective function is 8688039
# convert the solution to a transport matrix
mSol <- matrix(0, nLoc, nLoc)
mSol[lower.tri(mSol)] <- lpSol$solution
mSol[upper.tri(mSol)] <- t(mSol)[upper.tri(mSol)]
mSol
#> [,1] [,2] [,3] [,4] [,5] [,6]
#> [1,] 0 1 1 1 0 0
#> [2,] 1 0 0 1 1 0
#> [3,] 1 0 0 0 1 1
#> [4,] 1 1 0 0 0 1
#> [5,] 0 1 1 0 0 1
#> [6,] 0 0 1 1 1 0
I am trying to add two matrices with different dimension in R. Ideally, the system should equate two matrices adding missing rows/columns, filled with zeros. For instance, if we have one matrix with 1:4 rows and another with 1:5 rows and their number of columns is identical. So to add the two matrices we need to add to the first matrix the fifth row full of zeros.
Could you please help.
#Matrix1
a11<-matrix(c(419371623, 10990236, 29346292, 0, 0, 39386246.52, 0, 0,0 ,0,0, 0, 0, 0, 30174248.77,0, 27839925.91, 0 ,0 ,112921829.5),4,5,dimnames = list(c(1,2,3,5),c(1,2,3,4,5)),byrow=TRUE)
#Matrix 2
a22<-matrix(c(853624485, 0, 766111,0, 0, 20240075.89 ,0, 4839059.2,0, 2062687.122 ,0, 0,0 ,0 ,0 ,7282484.458,0, 18738621.67 ,0 ,0),5,4,byrow=TRUE, list(c(1:5),c(1:4)))
#Expected Result:
res<- matrix(c(1272996108, 10990236, 30112402.72, 0, 0,
39386247, 20240075.89, 0, 48390599.21, 0,
0, 2062687.122 ,0, 0, 30174249,
0, 27839926, 0, 7282484.458, 112921830,
0, 18738622, 0, 0, 0), 5, 5, byrow=TRUE, dimnames = list(1:5,1:5)
You could write your own function to perform this:
`%+%` <- function(a, b){
i <- dim(a)
j <- dim(b)
out <- pmax(i,j)
valid <- pmin(i,j)
result <- matrix(0, out[1], out[2])
v_row <- seq(valid[1])
v_col <- seq(valid[2])
result[v_row, v_col] <- a[v_row, v_col] + b[v_row, v_col]
ind1 <- which(result[seq(i[1]), seq(i[2])] == 0 & a!=0, TRUE)
result[ind1] <- a[ind1]
ind2 <- which(result[seq(j[1]), seq(j[2])] == 0 & b!=0, TRUE)
result[ind2] <- b[ind2]
result
}
a11%+%a22
[,1] [,2] [,3] [,4] [,5]
[1,] 1272996108 10990236 30112403 0 0
[2,] 39386247 20240076 0 4839059 0
[3,] 0 2062687 0 0 30174249
[4,] 0 27839926 0 7282484 112921830
[5,] 0 18738622 0 0 0
s1 <- matrix(1,3,5)
s2 <- matrix(2, 5,2)
s1
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 1 1 1 1 1
[3,] 1 1 1 1 1
s2
[,1] [,2]
[1,] 2 2
[2,] 2 2
[3,] 2 2
[4,] 2 2
[5,] 2 2
s1 %+% s2
[,1] [,2] [,3] [,4] [,5]
[1,] 3 3 1 1 1
[2,] 3 3 1 1 1
[3,] 3 3 1 1 1
[4,] 2 2 0 0 0
[5,] 2 2 0 0 0
Maybe there is a shorter/better way to make the dimension of both the matrix equal but here is one way.
n <- max(ncol(a11), ncol(a22))
m <- max(nrow(a11), nrow(a22))
if(m > ncol(a11)) a11 <- cbind(a11, matrix(0, ncol = m - ncol(a11), nrow = nrow(a11)))
if(m > ncol(a22)) a22 <- cbind(a22, matrix(0, ncol = m - ncol(a22), nrow = nrow(a22)))
if(n > nrow(a11)) a11 <- rbind(a11, matrix(0, ncol = ncol(a11), nrow = n - nrow(a11)))
if(n > nrow(a22)) a11 <- rbind(a11, matrix(0, ncol = ncol(a12), nrow = n - nrow(a22)))
Now a11 and a22 are of same dimension so you can add them :
a11 + a22
# 1 2 3 4 5
#1 1272996108 10990236 30112403 0 0
#2 39386247 20240076 0 4839059 0
#3 0 2062687 0 0 30174249
#5 0 27839926 0 7282484 112921830
# 0 18738622 0 0 0
After initializing res to zero, I am adding the matrices by indices.
Easily extendable to add more matrices.
# initilize res
res <- matrix(0, nrow = max(nrow(a11), nrow(a22)),
ncol = max(ncol(a11), ncol(a22)))
# index of a11
inds <- which(!is.na(a11), arr.ind = T)
res[inds] <- res[inds] + a11[inds]
# index of a22
inds <- which(!is.na(a22), arr.ind = T)
res[inds] <- res[inds] + a22[inds]
# repeat for a33 etc if there's more.
Results with a11 and a22
> res
[,1] [,2] [,3] [,4] [,5]
[1,] 1272996108 10990236 30112403 0 0
[2,] 39386247 20240076 0 4839059 0
[3,] 0 2062687 0 0 30174249
[4,] 0 27839926 0 7282484 112921830
[5,] 0 18738622 0 0 0
I am looking for an easier way to do the following:
m <- matrix(0, nrow=3, 3)
v <- c(1, 3, 2)
for (i in 1:nrow(m)) {
m[[i, v[i]]] = 1
}
The above code creates the following index matrix:
[,1] [,2] [,3]
[1,] 1 0 0
[2,] 0 0 1
[3,] 0 1 0
There surely must be a better way to do this?!
One way to do it without pre-defining the matrix would be to use outer:
num.col <- 3
outer(v, seq_len(num.col), "==") * 1
# [,1] [,2] [,3]
# [1,] 1 0 0
# [2,] 0 0 1
# [3,] 0 1 0
Say I have a list of indices, like:
l <- list(c(1,2,3), c(1), c(1,5), c(2, 3, 5))
Which specify the non-zero elements in a matrix, like:
(m <- matrix(c(1,1,1,0,0, 1,0,0,0,0, 1,0,0,0,5, 0,1,1,0,1), nrow=4, byrow=TRUE))
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 0 0
[2,] 1 0 0 0 0
[3,] 1 0 0 0 5
[4,] 0 1 1 0 1
What is the fastest way, using R, to make m from l, giving that the matrix is very big, say 50.000 rows and 2000 columns?
Try
d1 <- stack(setNames(l, seq_along(l)))
library(Matrix)
m1 <- sparseMatrix(as.numeric(d1[,2]), d1[,1], x=1)
as.matrix(m1)
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 1 1 0 0
#[2,] 1 0 0 0 0
#[3,] 1 0 0 0 1
#[4,] 0 1 1 0 1
Or instead of stack, we could use melt
library(reshape2)
d2 <- melt(l)
sparseMatrix(d2[,2], d2[,1],x=1)
Or using only base R
Un1 <- unlist(l)
m1 <- matrix(0, nrow=length(l), ncol=max(Un1))
m1[cbind(as.numeric(d1$ind), d1$values)] <- 1
m1
For me, the following is at least 3 times faster than the suggestions above, on data the size as specified in the question (5e4 x 2e3):
unlist_l <- unlist(l)
M <- matrix(0, nrow = length(l), ncol = max(unique(unlist_l)))
ij <- cbind(rep(1:length(l), lengths(l)), unlist_l)
M[ij] <- 1
Performance might depend on data size and degree of sparsity.