weird output when partitioning a matrix into lists in R - r

I've been trying to write a function that takes in matrix (x) and a vector (cut.vec) and outputs a list, where each element of the list is a combination of some of the columns in the input matrix. Each element in the input vector is an index where want to partition the matrix. Then I want to save every partition to an element in a list and return that list.
Here's what I've got so far:
This is the actual function that I'm running:
make.cut <- function(x, cut.vec){
ran.once <- 0 #This checks for first run
out <- list() #This creates the output list
temp.matrix <- matrix() #For holding data
for(i in 1:length(cut.vec)){
for(n in 1:cut.vec[i]){
if(cut.vec[i]<n){
#Do nothing
}else{
hold <- x[,n]
if(ran.once != 0){
temp.matrix <- cbind(temp.matrix, hold)
}else{
temp.matrix <- hold
ran.once <- 1
}
}
}
out[[i]] <- temp.matrix
temp.matrix <- matrix()
}
return(out)
}
When I run this I get a list out, but only the first element is correct. Each element except the first one only contains one column of the input matrix.
**Example Input**
x<-matrix(c(341, 435, 834, 412, 245, 532.2, 683.4, 204.2, 562.7, 721.5, 149, 356, 112, 253, 211, 53, 92, 61, 84, 69), nrow=4)
x= 341 435 834 412 245
532.2 683.4 204.2 562.7 721.5
149 356 112 253 211
53 92 61 84 69
cut.vec = c(2, 3, 5)
out <- make.cut(x, cut.vec):
a <- out[[1]]
b <- out[[2]]
c <- out[[3]]
**Intended Output**
a= 341 435
532.2 683.4
149 356
53 92
b= 834
204.2
112
61
c= 412 245
562.7 721.5
253 211
84 69
**Actual Output**
a= 341 435
532.2 683.4
149 356
53 92
b= 435
683.4
356
92
c= 834
204.2
112
61
I can do this from the console manually, one element at a time and it works, but every time I try and do it with the make.cut function it breaks.
This is how I did it by hand in terminal:
cut.vec<-c(3, 5)
a<-x[,1]
b<-x[,2]
c<-x[,3]
temp <- cbind(a,b,c)
out[[1]] <- temp
cut.vec[2] is equal to 5
a<-x[,4]
b<-x[,5]
temp <- cbind(a,b)
out[[2]] <- temp
However, when I try to apply the same methodology in a function it breaks.

You can use the following approach to "cut" a matrix along a vector:
Example data:
mat <- matrix(1:16, nrow = 2)
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
# [1,] 1 3 5 7 9 11 13 15
# [2,] 2 4 6 8 10 12 14 16
cutvec <- c(2,5)
First, cut the column numbers of mat along cutvec:
cuts <- cut(seq(ncol(mat)), c(0, cutvec - 1))
Then you can create a list with subsets with tapply:
tapply(seq(ncol(mat)), cuts, function(x) mat[, x, drop = FALSE])
# $`(0,1]`
# [,1]
# [1,] 1
# [2,] 2
#
# $`(1,4]`
# [,1] [,2] [,3]
# [1,] 3 5 7
# [2,] 4 6 8

Related

How to sort every column in ascending order in R

M = matrix(data = c(6,34,923,5,0, 112:116, 5,9,34,76,2, 545:549), nrow = 4)
I want it to ascend into and become like this
Ascend for each column and this is the expected output
I'm assuming that you meant nrow = 5 cause that corresponds to the matrix you've shown. Then all you need to do is simply use apply() to sort each column
M = matrix(data = c(6,34,923,5,0, 112:116, 5,9,34,76,2, 545:549), nrow = 5)
apply(M, 2, sort)
[,1] [,2] [,3] [,4]
[1,] 0 112 2 545
[2,] 5 113 5 546
[3,] 6 114 9 547
[4,] 34 115 34 548
[5,] 923 116 76 549

Convert bigger dimension matrix to smaller dimension matrix with a loop

I currently have 185*185 matrix and the goal is to convert this matrix into a 35*35 matrix by aggregating the value based on the rows and cols of the 185 matrix.
Example:
I have a 8*8 matrix as below:
matrix_x <- matrix(1:64, nrow = 8)
Then I want to convert it into a 4*4 matrix:
matrix_y <- matrix(NA, nrow = 4, ncol = 4)
The list below is created for aggregating the 8*8 matrix cols to a 4*4 matrix
col_list <- list(
1,
2:3,
c(4,8),
5:7
)
What I've done to achieve this is by assigning the value manually as below
matrix_y[1,1] <- sum(matrix_x[col_list[[1]],col_list[[1]]])
matrix_y[1,2] <- sum(matrix_x[col_list[[1]],col_list[[2]]])
matrix_y[1,3] <- sum(matrix_x[col_list[[1]],col_list[[3]]])
matrix_y[1,4] <- sum(matrix_x[col_list[[1]],col_list[[4]]])
matrix_y[2,1] <- sum(matrix_x[col_list[[2]],col_list[[1]]])
matrix_y[2,2] <- sum(matrix_x[col_list[[2]],col_list[[2]]])
matrix_y[2,3] <- sum(matrix_x[col_list[[2]],col_list[[3]]])
matrix_y[2,4] <- sum(matrix_x[col_list[[2]],col_list[[4]]])
matrix_y[3,1] <- sum(matrix_x[col_list[[3]],col_list[[1]]])
matrix_y[3,2] <- sum(matrix_x[col_list[[3]],col_list[[2]]])
matrix_y[3,3] <- sum(matrix_x[col_list[[3]],col_list[[3]]])
matrix_y[3,4] <- sum(matrix_x[col_list[[3]],col_list[[4]]])
matrix_y[4,1] <- sum(matrix_x[col_list[[4]],col_list[[1]]])
matrix_y[4,2] <- sum(matrix_x[col_list[[4]],col_list[[2]]])
matrix_y[4,3] <- sum(matrix_x[col_list[[4]],col_list[[3]]])
matrix_y[4,4] <- sum(matrix_x[col_list[[4]],col_list[[4]]])
This approach works well, but I'm looking for a more efficient way to achieve this since the approach I've done takes so many code lines.
There should be a neater/easier way to do this but here is one straight-forward option :
n <- 4
t(sapply(seq_len(n), function(p) sapply(col_list, function(q) sum(matrix_x[p, q]))))
# [,1] [,2] [,3] [,4]
#[1,] 1 26 82 123
#[2,] 2 28 84 126
#[3,] 3 30 86 129
#[4,] 4 32 88 132
This gives the same matrix as matrix_y in the post.
For the updated question, we can use outer
apply_fun <- function(x, y) sum(matrix_x[x, y])
outer(col_list, col_list, Vectorize(apply_fun))
# [,1] [,2] [,3] [,4]
#[1,] 1 26 82 123
#[2,] 5 58 170 255
#[3,] 12 72 184 276
#[4,] 18 108 276 414
Or following the same approach as in original answer with nested sapply
t(sapply(col_list, function(p) sapply(col_list, function(q) sum(matrix_x[p, q]))))

Diagonal of a 3D array

How can one extract the "diagonal" from three-dimensional array in R? For a matrix (2D array) one can use the diag(...) function. In a similar way, given an N x N x M array, a natural operation is to convert it into an N x M matrix by taking the diagonal from each N x N slice and returning it as a matrix.
It's easy to do this using a loop, but that is not idiomatic R and is slow. Another possibility is to use slightly complex indexing (see my own answer to this question) but it is a bit hard to read. What other alternatives are there? Is there a standard R way to do this?
Create an array and fill it by some values:
> a=array(0,c(10,10,5))
> for (i in 1:10) for (j in 1:10) for (k in 1:5) a[i,j,k]=100*i+10*j+k-111
Run the apply function:
> apply(a,3,diag)
[,1] [,2] [,3] [,4] [,5]
[1,] 0 1 2 3 4
[2,] 110 111 112 113 114
[3,] 220 221 222 223 224
[4,] 330 331 332 333 334
[5,] 440 441 442 443 444
[6,] 550 551 552 553 554
[7,] 660 661 662 663 664
[8,] 770 771 772 773 774
[9,] 880 881 882 883 884
[10,] 990 991 992 993 994
Various diagonals:
A = array(1:12, c(2, 2, 3))
apply(A, 1, diag)
# [,1] [,2]
#[1,] 1 2
#[2,] 7 8
apply(A, 2, diag)
# [,1] [,2]
#[1,] 1 3
#[2,] 6 8
apply(A, 3, diag)
# [,1] [,2] [,3]
#[1,] 1 5 9
#[2,] 4 8 12
Although I'm not enamored of the term "3d.diagonal" for this result, it can be achieved with this simple function (up to identity modulo transpose):
arr <- array(1:27,c(3,3,3) )
apply(arr, 3, function(x) x[row(x)==col(x)] )
# returns same value as diag.3d (arr)
[,1] [,2] [,3]
[1,] 1 10 19
[2,] 5 14 23
[3,] 9 18 27
I think a "real diagonal" would be arr[ cbind(1:3,1:3,1:3) ]
One possible approach is to use indexing, where the indices are a matrix with three columns. For example:
diag.3d <- function(A) {
# Expect a N x N x M array
stopifnot(length(dim(A)) == 3)
n <- nrow(A)
stopifnot(n == ncol(A))
m <- dim(A)[3]
IXS <- cbind(1:n, 1:n, rep(1:m, each = n))
cn <- colnames(A)
rn <- dimnames(A)[[3]]
matrix(A[IXS], ncol = n, byrow = T, dimnames = list(rn, cn))
}
Although indices (in variable IXS) seem hard to read.
Another approach is subseting the 3 dimensions array with a 2 dimensions matrix:
a <- array(1:100,dim = c(5,5,4))
ref <- cbind(1:5,1:5,rep(1:4,each= 5))
a[ref]
Output is a vector instead of a matrix. On my computer it is more efficient than apply() and you can also fill the diagonal values.

Find the largest values on a matrix in R

I am working on a matrix in R, 230 x 230 and I want to extract the 10 (or any other number than 1) max inputs on the matrix, both their position and value.
The extra problem is that this is a similarity matrix, so I have 1s in the diagonal which of course I want to leave out of the max search.
Any ideas or commands for that?
A neat way to do this in general is with the underused arrayInd function, which gives you row and column positions for plain jane vector positions. That's how which(..., arr.ind = TRUE) does it. Here's how you might do it:
## creating a random 230x230 matrix
n <- 230;
set.seed(1);
m <- matrix(sample.int(100000, n*n, replace = TRUE), n, n);
diag(m) <- 1;
## function to return n largest values and position for matrix m
nlargest <- function(m, n, sim = TRUE) {
mult <- 1;
if (sim) mult <- 2;
res <- order(m)[seq_len(n) * mult];
pos <- arrayInd(res, dim(m), useNames = TRUE);
list(values = m[res],
position = pos)
}
diag(m) <- NA;
nlargest(m, 10);
# $values
# [1] 1 2 11 12 12 12 13 18 21 22
#
# $position
# row col
# [1,] 59 95
# [2,] 178 202
# [3,] 160 34
# [4,] 83 151
# [5,] 150 194
# [6,] 18 225
# [7,] 13 38
# [8,] 206 182
# [9,] 89 22
#[10,] 142 99

Sum Every N Values in Matrix

So I have taken a look at this question posted before which was used for summing every 2 values in each row in a matrix. Here is the link:
sum specific columns among rows. I also took a look at another question here: R Sum every k columns in matrix which is more similiar to mine. I could not get the solution in this case to work. Here is the code that I am working with...
y <- matrix(1:27, nrow = 3)
y
m1 <- as.matrix(y)
n <- 3
dim(m1) <- c(nrow(m1)/n, ncol(m1), n)
res <- matrix(rowSums(apply(m1, 1, I)), ncol=n)
identical(res[1,],rowSums(y[1:3,]))
sapply(split.default(y, 0:(length(y)-1) %/% 3), rowSums)
I just get an error message when applying this. The desired output is a matrix with the following values:
[,1] [,2] [,3]
[1,] 12 39 66
[2,] 15 42 69
[3,] 18 45 72
To sum consecutive sets of n elements from each row, you just need to write a function that does the summing and apply it to each row:
n <- 3
t(apply(y, 1, function(x) tapply(x, ceiling(seq_along(x)/n), sum)))
# 1 2 3
# [1,] 12 39 66
# [2,] 15 42 69
# [3,] 18 45 72
Transform the matrix to an array and use colSums (as suggested by #nongkrong):
y <- matrix(1:27, nrow = 3)
n <- 3
a <- y
dim(a) <- c(nrow(a), ncol(a)/n, n)
b <- aperm(a, c(2,1,3))
colSums(b)
# [,1] [,2] [,3]
#[1,] 12 39 66
#[2,] 15 42 69
#[3,] 18 45 72
Of course this assumes that ncol(y) is divisible by n.
PS: You can of course avoid creating so many intermediate objects. They are there for didactic purposes.
I would do something similar to the OP -- apply rowSums on subsets of the matrix:
n = 3
ng = ncol(y)/n
sapply( 1:ng, function(jg) rowSums(y[, (jg-1)*n + 1:n ]))
# [,1] [,2] [,3]
# [1,] 12 39 66
# [2,] 15 42 69
# [3,] 18 45 72

Resources