Related
This question already has answers here:
3 Dimensional Array Names in R
(2 answers)
Closed 6 years ago.
I have a existing array that I made and I want to name the dimensions of this array. I can't use the dimnames= argument of array() because I need to make this array with a different function. I need to rename the dimensions with something similar to this names(my.array)<-my.names.
Thanks for the help (and I'm new to this if you can't already tell)
Use dimnames(x) <- list(d1names, d2names, ...) where d1names, d2names and so forth are character vectors whose lengths match the lengths of your dimensions.
If your array is bidimensional (a matrix), you can use rownames(x) <- d1names and colnames(x) <- d2names instead.
Example:
> A <- outer(outer(1:3,1:4),1:2)
> A
, , 1
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 2 4 6 8
[3,] 3 6 9 12
, , 2
[,1] [,2] [,3] [,4]
[1,] 2 4 6 8
[2,] 4 8 12 16
[3,] 6 12 18 24
> dimnames(A)
NULL
> dimnames(A) <- list(LETTERS[1:3],LETTERS[1:4],LETTERS[1:2])
> A
, , A
A B C D
A 1 2 3 4
B 2 4 6 8
C 3 6 9 12
, , B
A B C D
A 2 4 6 8
B 4 8 12 16
C 6 12 18 24
Example with matrix:
> B <- matrix(1:12,3,4)
> B
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
> rownames(B) <- letters[1:3]
> B
[,1] [,2] [,3] [,4]
a 1 4 7 10
b 2 5 8 11
c 3 6 9 12
> colnames(B) <- LETTERS[1:4]
> B
A B C D
a 1 4 7 10
b 2 5 8 11
c 3 6 9 12
you can still use dimnames<-
For example:
someArray <- array(1:30, dim=c(2, 3, 5))
dimnames(someArray) <- list(c("Hello", "World"), LETTERS[6:8], letters[1:5])
someArray
# , , a
# F G H
# Hello 1 3 5
# World 2 4 6
# , , b
# F G H
# Hello 7 9 11
# World 8 10 12
# , , c
# F G H
# Hello 13 15 17
# World 14 16 18
# , , d
# F G H
# Hello 19 21 23
# World 20 22 24
# , , e
# F G H
# Hello 25 27 29
# World 26 28 30
I would like to write a function that takes columns and rows of matrices as arguments and gives a matrix as an output.
For example, a function that takes rows i of an m by k matrix A and columns j of a k by n matrix B, and return a matrix M with elements m_i,j that equals to min(A[i,] * B[,j]) (element-wise multiplication):
Is there any simple way to avoid using loops? Does an sapply equivalent for matrices exists?
> matrix_A
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 2 3 4 5 6
[3,] 3 4 5 6 7
[4,] 0 1 2 3 4
[5,] 5 6 7 8 9
> matrix_B
[,1] [,2] [,3] [,4] [,5]
[1,] 7 6 5 4 3
[2,] 6 5 4 3 2
[3,] 1 2 3 4 5
[4,] 8 7 6 5 4
[5,] 9 8 7 6 5
>
> output_matrix <- matrix(, nrow=nrow(matrix_A), ncol=ncol(matrix_B))
> for (row_i in 1:nrow(matrix_A)) {
+ for (col_j in 1:ncol(matrix_B)) {
+ output_matrix[row_i, col_j] <- min(matrix_A[row_i,]*matrix_B[,col_j])
+ }
+ }
> output_matrix
[,1] [,2] [,3] [,4] [,5]
[1,] 3 6 5 4 3
[2,] 4 8 10 8 6
[3,] 5 10 15 12 8
[4,] 0 0 0 0 0
[5,] 7 14 21 18 12
>
Using apply from base R,
apply(m2, 2, function(i) apply(m1, 1, function(j) min(j*i)))
which gives,
[,1] [,2] [,3] [,4] [,5]
[1,] 3 6 5 4 3
[2,] 4 8 10 8 6
[3,] 5 10 15 12 8
[4,] 0 0 0 0 0
[5,] 7 14 21 18 12
A fully vectorized solution can be,
t(matrix(do.call(pmin,
as.data.frame(
do.call(rbind, rep(split(m1, 1:nrow(m1)), each = 5)) * do.call(rbind, rep(split(t(m2), 1:nrow(m2)), 5)))),
nrow(m1)))
You can avoid R loops (*apply functions are loops too) for this specific example. Often an efficient solution is possible, but needs a specific algorithm as I demonstrate here. If you don't need to optimize speed, use loops. Your for loop offers the best readability and is easy to understand.
matrix_A <- matrix(c(1,2,3,0,5,
2,3,4,1,6,
3,4,5,2,7,
4,5,6,3,8,
5,6,7,4,9), 5)
matrix_B <- matrix(c(7,6,1,8,9,
6,5,2,7,8,
5,4,3,6,7,
4,3,4,5,6,
3,2,5,4,5), 5)
#all combinations of i and j
inds <- expand.grid(seq_len(nrow(matrix_A)), seq_len(ncol(matrix_B)))
#subset A and transposed B then multiply the resulting matrices
#then calculate rowwise min and turn result into a matrix
library(matrixStats)
matrix(rowMins(matrix_A[inds[[1]],] * t(matrix_B)[inds[[2]],]), nrow(matrix_A))
# [,1] [,2] [,3] [,4] [,5]
#[1,] 3 6 5 4 3
#[2,] 4 8 10 8 6
#[3,] 5 10 15 12 8
#[4,] 0 0 0 0 0
#[5,] 7 14 21 18 12
We use expand.grid to create all possible combinations of row and col pairs. We then use mapply to multiply all the row-column combination element wise and then select the min from it.
mat <- expand.grid(1:nrow(A),1:nrow(B))
mapply(function(x, y) min(matrix_A[x,] * matrix_B[, y]) , mat[,1], mat[,2])
#[1] 3 4 5 0 7 6 8 10 0 14 5 10 15 0 21 4 8 12 0 18 3 6 8 0 12
Assuming matrix_A, matrix_B and output_matrix all have the same dimensions we can relist the output from mapply to get the original dimensions.
output_matrix <- mapply(function(x, y) min(matrix_A[x,] * matrix_B[, y]),
mat[,1], mat[,2])
relist(output_matrix, matrix_A)
# [,1] [,2] [,3] [,4] [,5]
#[1,] 3 6 5 4 3
#[2,] 4 8 10 8 6
#[3,] 5 10 15 12 8
#[4,] 0 0 0 0 0
#[5,] 7 14 21 18 12
Here we use pmap to iterate over the rows and columns of A and B:
library(tidyverse)
pmap_dbl(expand.grid(1:nrow(A), 1:nrow(B)), ~ min(A[..1, ] * B[ , ..2])) %>%
matrix(nrow=5)
[,1] [,2] [,3] [,4] [,5]
[1,] 3 6 5 4 3
[2,] 4 8 10 8 6
[3,] 5 10 15 12 8
[4,] 0 0 0 0 0
[5,] 7 14 21 18 12
This question already has answers here:
Creating a symmetric matrix in R
(7 answers)
Closed 5 years ago.
I know A'A will give a symmetric positive definite matrix. But how can I generate random matrix in R that is symmetric, but not necessary to be positive definite?
The details will of course depend on what distribution you'll want the matrix elements to have, but once you settle on that, you can adapt something like the following:
m <- matrix(sample(1:20, 36, replace=TRUE), nrow=6)
m[lower.tri(m)] <- t(m)[lower.tri(m)]
m
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] 19 20 15 6 5 14
# [2,] 20 20 20 3 18 17
# [3,] 15 20 6 5 11 3
# [4,] 6 3 5 6 9 20
# [5,] 5 18 11 9 10 2
# [6,] 14 17 3 20 2 7
For ease of use, you can then wrap up code like that in a function, like so:
f <- function(n) {
m <- matrix(sample(1:20, n^2, replace=TRUE), nrow=n)
m[lower.tri(m)] <- t(m)[lower.tri(m)]
m
}
## Try it out
f(2)
# [,1] [,2]
# [1,] 9 13
# [2,] 13 15
f(3)
# [,1] [,2] [,3]
# [1,] 1 8 3
# [2,] 8 13 5
# [3,] 3 5 14
I have a sparse matrix represented as
> (f <- data.frame(row=c(1,2,3,1,2,1,2,3,4,1,1,2),value=1:12))
row value
1 1 1
2 2 2
3 3 3
4 1 4
5 2 5
6 1 6
7 2 7
8 3 8
9 4 9
10 1 10
11 1 11
12 2 12
Here the first column is always present (in fact, the first few are present, the rest are not).
I want to get the data into the matrix format:
> t(matrix(c(1,2,3,NA,4,5,NA,NA,6,7,8,9,10,NA,NA,NA,11,12,NA,NA),nrow=4,ncol=5))
[,1] [,2] [,3] [,4]
[1,] 1 2 3 NA
[2,] 4 5 NA NA
[3,] 6 7 8 9
[4,] 10 NA NA NA
[5,] 11 12 NA NA
Here is what seems to be working:
> library(Matrix)
> as.matrix(sparseMatrix(i = cumsum(f[[1]] == 1), j=f[[1]], x=f[[2]]))
[,1] [,2] [,3] [,4]
[1,] 1 2 3 0
[2,] 4 5 0 0
[3,] 6 7 8 9
[4,] 10 0 0 0
[5,] 11 12 0 0
Except that I have to replace 0 with NA myself.
Is there a better solution?
You can do everything with base functions. The trick is to use indexing by a 2-col (row and col indices) matrix:
j <- f$row
i <- cumsum(j == 1)
x <- f$value
m <- matrix(NA, max(i), max(j))
m[cbind(i, j)] <- x
m
Whether it is better or not than using the Matrix package is subjective. Overkill in my opinion if you are not doing anything else with it. Also if your data had 0 in the f$value column, they would end up being converted as NA if you are not too careful.
I have a matrix
df<-matrix(data=c(3,7,5,0,1,0,0,0,0,8,0,9), ncol=2)
rownames(df)<-c("a","b","c","d","e","f")
[,1] [,2]
a 3 0
b 7 0
c 5 0
d 0 8
e 1 0
f 0 9
and I would like to order the matrix in descending order first by column 1 and then by column two resulting in the matrix
df.ordered<-matrix(data=c(7,5,3,1,0,0,0,0,0,0,9,8),ncol=2)
rownames(df.ordered)<-c("b","c","a","e","f","d")
[,1] [,2]
b 7 0
c 5 0
a 3 0
e 1 0
f 0 9
d 0 8
Any suggestions on how I could achieve this? Thanks.
The order function should do it.
df[order(df[,1],df[,2],decreasing=TRUE),]
To complete the main answer, here is a way to do it programmatically, without having to specify the columns by hand:
set.seed(2013) # preparing my example
mat <- matrix(sample.int(10,size = 30, replace = T), ncol = 3)
mat
[,1] [,2] [,3]
[1,] 5 1 6
[2,] 10 3 1
[3,] 8 8 1
[4,] 8 9 9
[5,] 3 7 3
[6,] 8 8 5
[7,] 10 10 2
[8,] 8 10 7
[9,] 10 1 9
[10,] 9 4 5
As a simple example, let say I want to use all the columns in their order of appearance to sort the rows of the matrix: (One could easily give a vector of indexes to the matrix)
mat[do.call(order, as.data.frame(mat)),] #could be ..as.data.frame(mat[,index_vec])..
[,1] [,2] [,3]
[1,] 3 7 3
[2,] 5 1 6
[3,] 8 8 1
[4,] 8 8 5
[5,] 8 9 9
[6,] 8 10 7
[7,] 9 4 5
[8,] 10 1 9
[9,] 10 3 1
[10,] 10 10 2
order function will help you out, try this:
df[order(-df[,1],-df[,2]),]
[,1] [,2]
b 7 0
c 5 0
a 3 0
e 1 0
f 0 9
d 0 8
The minus before df indicates that the order is decreasing. You will get the same result setting decreasing=TRUE.
df[order(df[,1],df[,2],decreasing=TRUE),]