I am trying to do conditional subtraction of matrices in R. Let's say I have a list of matrices A, B, C. If my selection = 1, then C = A - B. Here are my codes:
selection = 1
A <- matrix(c(1:10), nrow = 5, ncol = 2)
A
B <- matrix(c(11:20), nrow = 5, ncol = 2)
B
C <- matrix(0, nrow = 5, ncol = 2)
C
my_matrix_name <- as.vector(c("A", "B", "C"))
my_list = list(A, B, C)
names(my_list) <- my_matrix_name
my_list$C <- ifelse(selection == 1, my_list$A - my_list$B, "Error")
The above codes yield the following results for my_list:
> my_list
$A
[,1] [,2]
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
$B
[,1] [,2]
[1,] 11 16
[2,] 12 17
[3,] 13 18
[4,] 14 19
[5,] 15 20
$C
[1] -10
But my desired output is like this:
> my_list
$A
[,1] [,2]
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
$B
[,1] [,2]
[1,] 11 16
[2,] 12 17
[3,] 13 18
[4,] 14 19
[5,] 15 20
$C
[,1] [,2]
[1,] -10 -10
[2,] -10 -10
[3,] -10 -10
[4,] -10 -10
[5,] -10 -10
Please help! Thanks!
Use if since the condition that you are checking is scalar and not a vector.
my_list$C <- if(selection == 1) my_list$A - my_list$B else 'Error'
my_list
#$A
# [,1] [,2]
#[1,] 1 6
#[2,] 2 7
#[3,] 3 8
#[4,] 4 9
#[5,] 5 10
#$B
# [,1] [,2]
#[1,] 11 16
#[2,] 12 17
#[3,] 13 18
#[4,] 14 19
#[5,] 15 20
#$C
# [,1] [,2]
#[1,] -10 -10
#[2,] -10 -10
#[3,] -10 -10
#[4,] -10 -10
#[5,] -10 -10
Related
Do you know an R function that sort each column of a matrix without using apply like this:
mat= matrix(c(1,2,0,-7,-4,7,8,3,12,15,23,-21),nrow = 4,ncol = 3)
apply(mat,2,sort)
##
[,1] [,2] [,3]
[1,] -7 -4 -21
[2,] 0 3 12
[3,] 1 7 15
[4,] 2 8 23
Do you also know a R function that return a vector of max of each column of a matrix without using apply like this?
mat2=matrix(c(2,1,0,-7,-4,7,8,3,12,15,23,-21),nrow = 3,ncol = 4)
apply(mat2,2,max)
##
[1] 2 7 12 23
Thanks.
If you really want to avoid using *apply family, here are several alternatives you can try
order method
> `dim<-`(mat[order(col(mat), mat)], dim(mat))
[,1] [,2] [,3]
[1,] -7 -4 -21
[2,] 0 3 12
[3,] 1 7 15
[4,] 2 8 23
> `dim<-`(mat2[order(col(mat2), -mat2)], dim(mat2))[1, ]
[1] 2 7 12 23
ave method
> ave(mat, col(mat), FUN = sort)
[,1] [,2] [,3]
[1,] -7 -4 -21
[2,] 0 3 12
[3,] 1 7 15
[4,] 2 8 23
> unique(ave(mat2, col(mat2), FUN = max))
[,1] [,2] [,3] [,4]
[1,] 2 7 12 23
> ave(mat2, col(mat2), FUN = max)[1, ]
[1] 2 7 12 23
aggregate method
> `dim<-`(unlist(aggregate(mat, list(rep(1, nrow(mat))), sort)[-1]), dim(mat))
[,1] [,2] [,3]
[1,] -7 -4 -21
[2,] 0 3 12
[3,] 1 7 15
[4,] 2 8 23
> unlist(aggregate(mat2, list(rep(1, nrow(mat2))), max)[-1])
V1 V2 V3 V4
2 7 12 23
One possibility for sorting is to use colSort from Rfast:
Rfast::colSort(mat)
[,1] [,2] [,3]
[1,] -7 -4 -21
[2,] 0 3 12
[3,] 1 7 15
[4,] 2 8 23
We can also use Rfast to get the max for each column:
Rfast::colMaxs(mat2, value = TRUE)
[1] 2 7 12 23
Another option for sorting is to use a simple for loop:
for(i in 1:ncol(mat)){
mat[,i] <- sort(mat[,i])
}
Could also use a simple for loop to get max:
max <- 0
for(i in 1:ncol(mat2)){
max[i] <- max(mat2[,i])
}
I have a list of matrices where most of the matrices are column matrices but some of them are row matrices. How to convert only those row matrices to column matrices? I would like to achieve this using base R.
Here is the list of matrices where the third one is a row matrix
x <- list(`1` = matrix(1:20, nrow=5), `2` = matrix(1:20, nrow=10), `3` = matrix(1:5, nrow=1))
How to convert the list to one like this:
$`1`
[,1] [,2] [,3] [,4] [,5]
[1,] 1 3 5 7 9
[2,] 2 4 6 8 10
$`2`
[,1] [,2]
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
$`3`
[1,] 1
[2,] 2
[3,] 3
[4,] 4
[5,] 5
I have a much larger dataset and so efficient code is preferred!
Check the dimensions of the matrix and transpose it if the row dimension is 1:
(y <- lapply(x, function(x) if(dim(x)[1] == 1) { t(x)} else x))
# $`1`
# [,1] [,2] [,3] [,4]
# [1,] 1 6 11 16
# [2,] 2 7 12 17
# [3,] 3 8 13 18
# [4,] 4 9 14 19
# [5,] 5 10 15 20
#
# $`2`
# [,1] [,2]
# [1,] 1 11
# [2,] 2 12
# [3,] 3 13
# [4,] 4 14
# [5,] 5 15
# [6,] 6 16
# [7,] 7 17
# [8,] 8 18
# [9,] 9 19
# [10,] 10 20
#
# $`3`
# [,1]
# [1,] 1
# [2,] 2
# [3,] 3
# [4,] 4
# [5,] 5
Let's start with an exemplary multi-dimensional array like
a <- array(1:24, dim = c(3, 2, 2, 2)); a
, , 1, 1
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
, , 2, 1
[,1] [,2]
[1,] 7 10
[2,] 8 11
[3,] 9 12
, , 1, 2
[,1] [,2]
[1,] 13 16
[2,] 14 17
[3,] 15 18
, , 2, 2
[,1] [,2]
[1,] 19 22
[2,] 20 23
[3,] 21 24
Now I want to cbind or rbind the first two dimensions, which are matrices over the remaining dimensions 3 and 4, to an entire data.frame.
The resulting data.frame should like this using rbind:
[,1] [,2]
[1, ] 1 4
[2, ] 2 5
[3, ] 3 6
[4, ] 7 10
[5, ] 8 11
[6, ] 9 12
...
What would be an efficient way to bind the first two dimensions of a multi-dimensional array to an entire structure like data.frame? Please consider that the array can have any number of dimensions greater than 2, and not only 4 like in the above given example.
Thanks in advance
You can use apply:
apply(a, 2, identity)
# [,1] [,2]
# [1,] 1 4
# [2,] 2 5
# [3,] 3 6
# [4,] 7 10
# [5,] 8 11
# [6,] 9 12
# [7,] 13 16
# [8,] 14 17
# [9,] 15 18
#[10,] 19 22
#[11,] 20 23
#[12,] 21 24
Permuting and modifying dimensions is quite efficient:
a <- array(1:24, dim = c(3, 2, 2, 2))
a <- aperm(a, c(2, 1, 3, 4))
dim(a) <- c(dim(a)[1], prod(dim(a)[-1]))
t(a)
# [,1] [,2]
# [1,] 1 4
# [2,] 2 5
# [3,] 3 6
# [4,] 7 10
# [5,] 8 11
# [6,] 9 12
# [7,] 13 16
# [8,] 14 17
# [9,] 15 18
#[10,] 19 22
#[11,] 20 23
#[12,] 21 24
I have a list of which consists of list of matrices as follows:
$A
$A[[1]]
$A[[1]][[1]]
[,1] [,2]
[1,] 1 6
[2,] 2 7
[3,] 3 8
[4,] 4 9
[5,] 5 10
$A[[2]]
$A[[2]][[1]]
[,1] [,2]
[1,] 2 7
[2,] 3 8
[3,] 4 9
[4,] 5 10
[5,] 6 11
$B
$B[[1]]
$B[[1]][[1]]
[,1] [,2]
[1,] 11 16
[2,] 12 17
[3,] 13 18
[4,] 14 19
[5,] 15 20
$B[[2]]
$B[[2]][[1]]
[,1] [,2]
[1,] 12 17
[2,] 13 18
[3,] 14 19
[4,] 15 20
[5,] 16 21
$C
$C[[1]]
$C[[1]][[1]]
[,1] [,2]
[1,] 0 0
[2,] 0 0
[3,] 0 0
[4,] 0 0
[5,] 0 0
$C[[2]]
$C[[2]][[1]]
[,1] [,2]
[1,] 0 0
[2,] 0 0
[3,] 0 0
[4,] 0 0
[5,] 0 0
The above list of matrices was created using the codes below:
A_mat1 <- matrix(as.numeric(c(1:10)), nrow = 5, ncol = 2)
B_mat1 <- matrix(as.numeric(c(11:20)), nrow = 5, ncol = 2)
C_mat1 <- matrix(as.numeric(0), nrow = 5, ncol = 2)
A_mat2 <- matrix(as.numeric(c(2:11)), nrow = 5, ncol = 2)
B_mat2 <- matrix(as.numeric(c(12:21)), nrow = 5, ncol = 2)
C_mat2 <- matrix(as.numeric(0), nrow = 5, ncol = 2)
my_matrix_name <- as.vector(c("A_mat1", "B_mat1", "C_mat1", "A_mat2", "B_mat2", "C_mat2"))
my_list = list(A_mat1, B_mat1, C_mat1, A_mat2, B_mat2, C_mat2)
names(my_list) <- my_matrix_name
my_A <- as.vector(my_matrix_name[substring(my_matrix_name,1,1) == "A"])
my_B <- as.vector(my_matrix_name[substring(my_matrix_name,1,1) == "B"])
my_C <- as.vector(my_matrix_name[substring(my_matrix_name,1,1) == "C"])
A = list()
for(i in seq_len(length(my_A))){
A[[i]] <- list(my_list[[paste0(my_A[[i]])]])
}
B = list()
for(i in seq_len(length(my_B))){
B[[i]] <- list(my_list[[paste0(my_B[[i]])]])
}
C = list()
for(i in seq_len(length(my_C))){
C[[i]] <- list(my_list[[paste0(my_C[[i]])]])
}
my_group = list(A,B,C)
names(my_group) <- c("A", "B", "C")
my_group
Where group C matrices have values of 0. Now I want to create a formula to overwrite group C equals to group A minus group B i.e. C = A - B
I have tried using
my_group[[3]] = my_group[[1]] - my_group[[2]]
and
my_group[[3]] = Map("-", my_group[[1]] , my_group[[2]])
but it gives error message: non-numeric argument to binary operator. Can anyone help me please? Thanks!
Because you have nested lists, your Map function is actually trying to subtract a list from another list. You need your mapping function to extract the first element of each list and subtract those
Map(function(A, B) A[[1]] - B[[1]], my_group$A , my_group$B)
#> [[1]]
#> [,1] [,2]
#> [1,] -10 -10
#> [2,] -10 -10
#> [3,] -10 -10
#> [4,] -10 -10
#> [5,] -10 -10
#>
#> [[2]]
#> [,1] [,2]
#> [1,] -10 -10
#> [2,] -10 -10
#> [3,] -10 -10
#> [4,] -10 -10
#> [5,] -10 -10
An option with pmap
library(purrr)
pmap(my_group[c('A', 'B')], ~ ..1[[1]] - ..2[[1]])
#[[1]]
# [,1] [,2]
#[1,] -10 -10
#[2,] -10 -10
#[3,] -10 -10
#[4,] -10 -10
#[5,] -10 -10
#[[2]]
# [,1] [,2]
#[1,] -10 -10
#[2,] -10 -10
#[3,] -10 -10
#[4,] -10 -10
#[5,] -10 -10
Suppose I have a matrix m and a positive integer vector v, what I want to do is get a new matrix m_new and each row of m (say m[i, ]) are replicated by v[i] times in m_new. For example:
m = matrix(1:6, nrow = 3)
## [,1] [,2]
## [1,] 1 4
## [2,] 2 5
## [3,] 3 6
v = c(3, 1, 2)
And m_new should be:
[,1] [,2]
[1,] 1 4 # m[1, ] is replicated by
[2,] 1 4 # v[1] = 3
[3,] 1 4 # times
[4,] 2 5
[5,] 3 6
[6,] 3 6
A for loop will make it for the small case:
m_new = matrix(0, sum(v), ncol(m))
k = 1
for(i in 1:nrow(m)){
for(j in k:(k+v[i]-1)){
m_new[j, ] = m[i, ]
}
k = k + v[i]
}
, but the row number of m in real world is usually big. Is there any effient way to do this?
m[rep(1:nrow(m), times = v), ]
# [,1] [,2]
# [1,] 1 4
# [2,] 1 4
# [3,] 1 4
# [4,] 2 5
# [5,] 3 6
# [6,] 3 6
> m <- matrix(1:25, ncol=5)
> m
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 2 7 12 17 22
[3,] 3 8 13 18 23
[4,] 4 9 14 19 24
[5,] 5 10 15 20 25
> apply(m, 2, function(c) rep(c,v))
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 2 7 12 17 22
[3,] 2 7 12 17 22
[4,] 3 8 13 18 23
[5,] 3 8 13 18 23
[6,] 3 8 13 18 23
[7,] 4 9 14 19 24
[8,] 4 9 14 19 24
[9,] 4 9 14 19 24
[10,] 4 9 14 19 24
[11,] 5 10 15 20 25
[12,] 5 10 15 20 25
[13,] 5 10 15 20 25
[14,] 5 10 15 20 25
[15,] 5 10 15 20 25