R recursively run an unknown sized nested loop - r

I am not sure if this is possible, but I thought I might post it anyway. Currently I am trying to write a code that will run a nested sort. The problem is, I don't know how many nested loops will need to run, it can vary from 2-7 sorting criteria.
Each loop of the function creates a data set that the lower loops will then use. I know this needs to be done using recursion, but I am having an extremely hard time getting this to work. Any help would be appreciated!
library(abind)
re <- c(5,5,5)
answer = matrix(0,5,5)
for(a in 1:4){
answer <- abind(answer,matrix(0,5,5),along=3)
}
for( i in 1:re[1]){
first <- c(1:re[1])
for(j in 1:re[2]){
if(j %in% first == 1){
second = j
}
print(second)
for(k in 1:re[3]){
if(k == second){
answer[k,j,i] <- k
}
}
}
}
answer
Output
answer
, , 1
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 0 2 0 0 0
[3,] 0 0 3 0 0
[4,] 0 0 0 4 0
[5,] 0 0 0 0 5
, , 2
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 0 2 0 0 0
[3,] 0 0 3 0 0
[4,] 0 0 0 4 0
[5,] 0 0 0 0 5
, , 3
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 0 2 0 0 0
[3,] 0 0 3 0 0
[4,] 0 0 0 4 0
[5,] 0 0 0 0 5
, , 4
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 0 2 0 0 0
[3,] 0 0 3 0 0
[4,] 0 0 0 4 0
[5,] 0 0 0 0 5
, , 5
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 0 2 0 0 0
[3,] 0 0 3 0 0
[4,] 0 0 0 4 0
[5,] 0 0 0 0 5

Related

r removing symmetrical elements of a matrix

I'm trying to combine two adjacency matrices leaving out the symmetric intersections.
M1<-matrix(c(0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0),nrow=5,ncol=5,byrow=T)
M2<-matrix(c(0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0),nrow=5,ncol=5,byrow=T)
The question is : how to reach the matrix below which "forgets" ([1,2],[2,1]) and displays only ones and zeros ?
My final result should be :
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 0 0
[2,] 0 0 0 0 0
[3,] 1 0 0 0 0
[4,] 1 0 0 0 1
[5,] 0 0 0 0 0
I've tried all sorts of additions and substractions involving t(M2) but there is always something wrong.
M = M1+M2
M[M==t(M)]=0
+(M>0)
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 0 0
[2,] 0 0 0 0 0
[3,] 1 0 0 0 0
[4,] 1 0 0 0 1
[5,] 0 0 0 0 0
Thanks to Onyambu. Applying your solution to my MClist of 40 (Mn,Nn) pairs, seems to work in this way:
AddMC<-lapply(1:40, function(x){
(MClist[[x]][[1]]+MClist[[x]][[2]])
})
InterMC<-lapply(1:40, function(x){
AddMC[[x]][AddMC[[x]]==t(AddMC[[x]])]=0
+(AddMC[[x]]>0)
})

Creating a list of similar diagonal block matrices in R

I have a smaller kxk matrix m given from which I want to create multiple larger NxN diagonal block matrices Q1, Q2, ..., QN. It is ensured that N is always a multiple of k.
A simple example should illustrate better what I mean:
m <- matrix(c(1,3,2,4),2,2) # the small kxk matrix
m
[,1] [,2]
[1,] 1 2
[2,] 3 4
And I want to get for let's say a 6x6 matrix the following diagonal block matrices:
Q1
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 2 0 0 0 0
[2,] 3 4 0 0 0 0
[3,] 0 0 0 0 0 0
[4,] 0 0 0 0 0 0
[5,] 0 0 0 0 0 0
[6,] 0 0 0 0 0 0
Q2
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0 0 0 0 0 0
[2,] 0 0 0 0 0 0
[3,] 0 0 1 2 0 0
[4,] 0 0 3 4 0 0
[5,] 0 0 0 0 0 0
[6,] 0 0 0 0 0 0
Q3
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0 0 0 0 0 0
[2,] 0 0 0 0 0 0
[3,] 0 0 0 0 0 0
[4,] 0 0 0 0 0 0
[5,] 0 0 0 0 1 2
[6,] 0 0 0 0 3 4
Any ideas how I could achieve this e.g. with lapply such that I can do the same for large matrices?
We can do this with bdiag from Matrix
library(Matrix)
lst <- list(bdiag(m, diag(4)*0), bdiag(0*diag(2), m, 0*diag(2)), bdiag(diag(4)*0, m))
If we want to change it to matrix, then use as.matrix
lapply(lst, as.matrix)
Also, this can be created as a single sparseMatrix
bdiag(list(m, 0*diag(6))[rep(1:2, length.out=5)])

Writing a vector to 3rd dimension of a 3D array in R

I am working on a multi-band Raster image. For the processing Raster is converted to matrix and then pixel wise processed. I am facing problem in writing the pixel values to the blank 3d array which is explained below.
let us assume
I have a blank 3D array
x = array(0,c(4,5,3))
x
, , 1
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 0 0
[2,] 0 0 0 0 0
[3,] 0 0 0 0 0
[4,] 0 0 0 0 0
, , 2
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 0 0
[2,] 0 0 0 0 0
[3,] 0 0 0 0 0
[4,] 0 0 0 0 0
, , 3
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 0 0
[2,] 0 0 0 0 0
[3,] 0 0 0 0 0
[4,] 0 0 0 0 0
and a vector
y = c(5,14)
I want to copy values of y in the 3rd dimension of x so that output look like example given below
x
, , 1
[,1] [,2] [,3] [,4] [,5]
[1,] 5 0 0 0 0
[2,] 0 0 0 0 0
[3,] 0 0 0 0 0
[4,] 0 0 0 0 0
, , 2
[,1] [,2] [,3] [,4] [,5]
[1,] 14 0 0 0 0
[2,] 0 0 0 0 0
[3,] 0 0 0 0 0
[4,] 0 0 0 0 0
, , 3
[,1] [,2] [,3] [,4] [,5]
[1,] NA 0 0 0 0
[2,] 0 0 0 0 0
[3,] 0 0 0 0 0
[4,] 0 0 0 0 0
I have searched on the internet but I am not able to find any solution.

use of the [<- operator to modify a line of data

I have some data
data <- diag(5)
I want to use the [<- operator to change a line.
The result should be:
data[1,] <- 2
> data
[,1] [,2] [,3] [,4] [,5]
[1,] 2 2 2 2 2
[2,] 0 1 0 0 0
[3,] 0 0 1 0 0
[4,] 0 0 0 1 0
[5,] 0 0 0 0 1
I know I can do e.g.
`[<-`(data, i=1, j=3, 2)
which gives
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 8 0 0
[2,] 0 1 0 0 0
[3,] 0 0 1 0 0
[4,] 0 0 0 1 0
[5,] 0 0 0 0 1
but how can I operate on line (or column, same issue)?
I tried j=NULL, j=integer(0), it doesn't work. I could do j=1:5 and get what I want but I am wondering how to mimic data[1,] <- 2 and not data[1,1:5] <- 2.
> `[<-`(data, 1, , 2) # blank 2nd argument
[,1] [,2] [,3] [,4] [,5]
[1,] 2 2 2 2 2
[2,] 0 1 0 0 0
[3,] 0 0 1 0 0
[4,] 0 0 0 1 0
[5,] 0 0 0 0 1
You can use ncol to ensure that all columns are set:
`[<-`(data, i = 1, j = 1:ncol(data), 2)

Convert a string into a similarity matrix

I have number of strings in an idiosyncratic format, representing sets. In R, I'd like to convert them into a similarity matrix.
For example, a string showing that 1+2 comprise a set, 3 is alone in a set, and 4,5, and 6 comprise a set is:
"1+2,3,4+5+6"
For the example above, I'd like to be able to produce
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 0 0 0 0
[2,] 1 1 0 0 0 0
[3,] 0 0 1 0 0 0
[4,] 0 0 0 1 1 1
[5,] 0 0 0 1 1 1
[6,] 0 0 0 1 1 1
It seems like this should be a painfully simple task. How would I go about it?
Here's an approach:
out <- lapply(unlist(strsplit("1+2,3,4+5+6", ",")), function(x) {
as.numeric(unlist(strsplit(x, "\\+")))
})
x <- table(unlist(out), rep(seq_along(out), sapply(out, length)))
matrix(x %*% t(x), nrow(x))
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 1 1 0 0 0 0
## [2,] 1 1 0 0 0 0
## [3,] 0 0 1 0 0 0
## [4,] 0 0 0 1 1 1
## [5,] 0 0 0 1 1 1
## [6,] 0 0 0 1 1 1
Pseudocode:
Split at , to get an array of strings, each describing a set.
For each element of the array:
Split at + to get an array of set members
Mark every possible pairing of members of this set on the matrix
You can create a matrix in R with:
m = mat.or.vec(6, 6)
By default, the matrix should initialize with all entries 0. You can assign new values with:
m[2,3] = 1
Here's another approach:
# write a simple function
similarity <- function(string){
sets <- gsub("\\+", ":", strsplit(string, ",")[[1]])
n <- as.numeric(tail(strsplit(gsub("[[:punct:]]", "", string), "")[[1]], 1))
mat <- mat.or.vec(n, n)
ind <- suppressWarnings(lapply(sets, function(x) eval(parse(text=x))))
for(i in 1:length(ind)){
mat[ind[[i]], ind[[i]]] <- 1
}
return(mat)
}
# Use that function
> similarity("1+2,3,4+5+6")
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 1 0 0 0 0
[2,] 1 1 0 0 0 0
[3,] 0 0 1 0 0 0
[4,] 0 0 0 1 1 1
[5,] 0 0 0 1 1 1
[6,] 0 0 0 1 1 1
# Using other string
> similarity("1+2,3,5+6+7, 8")
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 0 0 0 0 0 0
[2,] 1 1 0 0 0 0 0 0
[3,] 0 0 1 0 0 0 0 0
[4,] 0 0 0 0 0 0 0 0
[5,] 0 0 0 0 1 1 1 0
[6,] 0 0 0 0 1 1 1 0
[7,] 0 0 0 0 1 1 1 0
[8,] 0 0 0 0 0 0 0 1

Resources