I have a vector comprised of a set of numbers, for example:
vec <- c(1, 2, 3, 4, 5)
I wish to produce a matrix that contains the sum of each pairwise element within that vector - in this case:
[,1] [,2] [,3] [,4] [,5]
[1,] 2 3 4 5 6
[2,] 3 4 5 6 7
[3,] 4 5 6 7 8
[4,] 5 6 7 8 9
[5,] 6 7 8 9 10
You can use outer()
outer(vec,vec,"+")
Output:
[,1] [,2] [,3] [,4] [,5]
[1,] 2 3 4 5 6
[2,] 3 4 5 6 7
[3,] 4 5 6 7 8
[4,] 5 6 7 8 9
[5,] 6 7 8 9 10
Note: this may also be written as:
outer(vec,vec,`+`)
Here's one way.
vec <- c(1, 2, 3, 4, 5)
matrix(rowSums(expand.grid(vec, vec)), ncol = length(vec))
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 2 3 4 5 6
#> [2,] 3 4 5 6 7
#> [3,] 4 5 6 7 8
#> [4,] 5 6 7 8 9
#> [5,] 6 7 8 9 10
sapply can do but maybe not as efficient as outer
> sapply(vec,`+`,vec)
[,1] [,2] [,3] [,4] [,5]
[1,] 2 3 4 5 6
[2,] 3 4 5 6 7
[3,] 4 5 6 7 8
[4,] 5 6 7 8 9
[5,] 6 7 8 9 10
Related
Suppose I have a list of nine, 2 x 2 matrices as defined by:
mat_list <- list(matrix(1, 2, 2), matrix(2, 2, 2), matrix(3, 2, 2),
matrix(4, 2, 2), matrix(5, 2, 2), matrix(6, 2, 2),
matrix(7, 2, 2), matrix(8, 2, 2), matrix(9, 2, 2))
I would like to merge these matrices into a single 6 x 6 matrix. It would look like this:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 4 4 7 7
[2,] 1 1 4 4 7 7
[3,] 2 2 5 5 8 8
[4,] 2 2 5 5 8 8
[5,] 3 3 6 6 9 9
[6,] 3 3 6 6 9 9
I can accomplish this task using the following code:
do.call( cbind, list( do.call( rbind, mat_list[1:3]),
do.call( rbind, mat_list[4:6]),
do.call( rbind, mat_list[7:9])) )
But how can this be generalized for a very large list of matrices? It would be too tedious to write out the list of do.call functions.
Maybe we can do like this
do.call(
cbind,
lapply(
split(mat_list, ceiling(seq_along(mat_list) / 3)),
function(x) do.call(rbind, x)
)
)
which gives
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 4 4 7 7
[2,] 1 1 4 4 7 7
[3,] 2 2 5 5 8 8
[4,] 2 2 5 5 8 8
[5,] 3 3 6 6 9 9
[6,] 3 3 6 6 9 9
or
> do.call(cbind, Map(function(x) do.call(rbind, x), data.frame(matrix(mat_list, 3, 3))))
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 4 4 7 7
[2,] 1 1 4 4 7 7
[3,] 2 2 5 5 8 8
[4,] 2 2 5 5 8 8
[5,] 3 3 6 6 9 9
[6,] 3 3 6 6 9 9
Goal
I want to use a long vector of numbers, to create a matrix where each column is a successive offset (lag or lead) of the original vector. If n is the maximum offset, the matrix will have dimensions [length(vector), n * 2 + 1] (because we want offsets in both directions, and include the 0 offset, i.e. the original vector).
Example
To illustrate, consider the following vector:
test <- c(2, 8, 1, 10, 7, 5, 9, 3, 4, 6)
[1] 2 8 1 10 7 5 9 3 4 6
Expected output
Now we create offsets of values, let's say for n == 3:
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] NA NA NA 2 8 1 10
[2,] NA NA 2 8 1 10 7
[3,] NA 2 8 1 10 7 5
[4,] 2 8 1 10 7 5 9
[5,] 8 1 10 7 5 9 3
[6,] 1 10 7 5 9 3 4
[7,] 10 7 5 9 3 4 6
[8,] 7 5 9 3 4 6 NA
[9,] 5 9 3 4 6 NA NA
[10,] 9 3 4 6 NA NA NA
I am looking for an efficient solution. data.table or tidyverse solutions more than welcome.
Returning only the rows that have no NA's (i.e. rows 4 to 7) is also ok.
Current solution
lags <- lapply(3:1, function(x) dplyr::lag(test, x))
leads <- lapply(1:3, function(x) dplyr::lead(test, x))
l <- c(lags, test, leads)
matrix(unlist(l), nrow = length(test))
In base R, you can use embed to get rows 4 through 7. You have to reverse the column order, however.
embed(test, 7)[, 7:1]
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 2 8 1 10 7 5 9
[2,] 8 1 10 7 5 9 3
[3,] 1 10 7 5 9 3 4
[4,] 10 7 5 9 3 4 6
data
test <- c(2, 8, 1, 10, 7, 5, 9, 3, 4, 6)
This will produce what you need...
n <- 3
t(embed(c(rep(NA,n), test, rep(NA,n)), length(test)))[length(test):1,]
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] NA NA NA 2 8 1 10
[2,] NA NA 2 8 1 10 7
[3,] NA 2 8 1 10 7 5
[4,] 2 8 1 10 7 5 9
[5,] 8 1 10 7 5 9 3
[6,] 1 10 7 5 9 3 4
[7,] 10 7 5 9 3 4 6
[8,] 7 5 9 3 4 6 NA
[9,] 5 9 3 4 6 NA NA
[10,] 9 3 4 6 NA NA NA
This can be solved by constructing the matrix from a long vector and returning only the wanted columns and rows:
test <- c(2, 8, 1, 10, 7, 5, 9, 3, 4, 6)
n_offs <- 3L
n_row <- length(test) + n_offs + 1L
matrix(rep(c(rep(NA, n_offs), test), n_row), nrow = n_row)[1:length(test), 1:(n_offs * 2L + 1L)]
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] NA NA NA 2 8 1 10
[2,] NA NA 2 8 1 10 7
[3,] NA 2 8 1 10 7 5
[4,] 2 8 1 10 7 5 9
[5,] 8 1 10 7 5 9 3
[6,] 1 10 7 5 9 3 4
[7,] 10 7 5 9 3 4 6
[8,] 7 5 9 3 4 6 NA
[9,] 5 9 3 4 6 NA NA
[10,] 9 3 4 6 NA NA NA
A variant which just returns the same result as embed(test, 7)[, 7:1] is:
matrix(rep(test, length(test) + 1L), nrow = length(test) + 1L)[
seq_len(length(test) - 2L * n_offs), seq_len(n_offs * 2L + 1L)]
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 2 8 1 10 7 5 9
[2,] 8 1 10 7 5 9 3
[3,] 1 10 7 5 9 3 4
[4,] 10 7 5 9 3 4 6
I'm trying to create a 6x6 matrix with the cell values equal to the sum of the row index and he col index. I can do this using loops, but I'm wondering if there is a way to do this using vector functions.
Use the outer function with "+":
outer(1:6, 1:6, "+")
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 2 3 4 5 6 7
[2,] 3 4 5 6 7 8
[3,] 4 5 6 7 8 9
[4,] 5 6 7 8 9 10
[5,] 6 7 8 9 10 11
[6,] 7 8 9 10 11 12
Incidentally, this is basically a shortcut for the following vectorized approach:
matrix(rep(1:6, 6) + rep(1:6, each = 6), nrow = 6)
Here's another possibility:
m <- matrix(NA,6,6)
m <- col(m)+row(m)
# [,1] [,2] [,3] [,4] [,5] [,6]
#[1,] 2 3 4 5 6 7
#[2,] 3 4 5 6 7 8
#[3,] 4 5 6 7 8 9
#[4,] 5 6 7 8 9 10
#[5,] 6 7 8 9 10 11
#[6,] 7 8 9 10 11 12
Let's say I have a simple vector
v <- 1:5
I can add the vector to each element within the vector with the following code to generate the resulting matrix.
matrix(rep(v, 5), nrow=5, byrow=T) + matrix(rep(v, 5), nrow=5)
[,1] [,2] [,3] [,4] [,5]
[1,] 2 3 4 5 6
[2,] 3 4 5 6 7
[3,] 4 5 6 7 8
[4,] 5 6 7 8 9
[5,] 6 7 8 9 10
But this seems verbose and inefficient. Is there a more concise way to accomplish this? Perhaps some linear algebra concept that is evading me?
outer should do what you want
outer(v, v, `+`)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 2 3 4 5 6
# [2,] 3 4 5 6 7
# [3,] 4 5 6 7 8
# [4,] 5 6 7 8 9
# [5,] 6 7 8 9 10
Posting this answer not for up votes but to highlight Franks comment. You can use
sapply(v,"+",v)
If I have a matrix say:
> mat1=matrix(1:12, ncol=3)
> mat1
[,1] [,2] [,3]
[1,] 1 5 9
[2,] 2 6 10
[3,] 3 7 11
[4,] 4 8 12
What do I do to replicate each column and put it next to the original so it looks like this:
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 5 5 9 9
[2,] 2 2 6 6 10 10
[3,] 3 3 7 7 11 11
[4,] 4 4 8 8 12 12
I'm sure this is really simple but can't see it! Many thanks.
Try this:
mat1=matrix(1:12, ncol=3)
mat1[,rep(1:ncol(mat1),each=2)]
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 1 1 5 5 9 9
## [2,] 2 2 6 6 10 10
## [3,] 3 3 7 7 11 11
## [4,] 4 4 8 8 12 12
Probably easiest to re-order a simple cbind:
cbind(mat, mat)[,order(rep(1:ncol(mat), times=2))]
or
mat[,rep(1:ncol(mat), each=2)]