How to riffle a matrix into another matrix [duplicate] - r

This question already has answers here:
interleave rows of matrix stored in a list in R
(2 answers)
Closed 9 years ago.
There is a function in Mathematica called "Riffle" that can be used for inserting columns of a matrix between columns of another matrix.For example, for m1 and m2 matrices like these:
m1= 1 1 1
1 1 1
1 1 1
m2=2 2 2
2 2 2
2 2 2
it creates
1 2 1 2 1 2
1 2 1 2 1 2
1 2 1 2 1 2
is there any equivalent function in R for doing this?

Assuming that you matrices have equal dimensions, you might use this little trick
m <- rbind(m1, m2)
dim(m) <- rev(dim(m))
m
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 2 1 2 1 2
[2,] 1 2 1 2 1 2
[3,] 1 2 1 2 1 2
Another option would be to use the interleave function from the gdata package. The function interleaves rows not columns, so you need to transpose your matrices back and forth.
m <- t(interleave(t(m1), t(m2)))
m
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 2 1 2 1 2
[2,] 1 2 1 2 1 2
[3,] 1 2 1 2 1 2

Don't know if it already exists (never seen it), but it is not to difficult to write:
riffle <- function(a,b) {
if (!all(dim(a) == dim(b))) stop("dimensions do not match")
array(rbind(a, b), dim=c(dim(a)[1], dim(a)[1]+dim(b)[1]))
}

Related

Quickly calculate the number of shared neighbor between any pair of nodes from an adjacency matrix

I'm wondering if there's a way to quickly calculate the number of shared neighbors between any pairs of nodes (i.e., the number of nodes connected to both node i and j) from an adjacency matrix (like the one below) and then return the output in matrix format?
I've referenced these following posts,
Find common neighbors of selected vertices
Counting the number of neighbors in common between two vertices in R
Calculate number of common neighbors in igraph R
but can't seem to find many clues to do what I want to achieve. I was told that this can be directly calculated as adjm'*adjm, but I am not sure if this makes sense. It will be really appreciated if someone could shed some light on this.
# create an adj. matrix
adjm <- matrix(sample(0:1, 100, replace=TRUE, prob=c(0.6,0.4)), nc=10)
# set diagonal element to 0
diag(adjm) <- 0
# making it symmetric
adjm[lower.tri(adjm)] = t(adjm)[lower.tri(adjm)]
Yes, you can get the number of shared neighbors by computing the matrix
product of adjm' and adjm. Since you are using R, adjm'*adjm means
the component-wise product of the matrices. We want the matrix product,
so you need to use %*%. I will use that below.
To simplify the notation, I will denote adjm = A where
A[i,j] is 1 if there is a link between nodes i and j (they are neighbors)
and A[i,j] = 0 otherwise.
Let's compute t(A) %*% A.
The i-jth coordinate of t(A) %*% A is
(t(A) %*% A)[i,j] =
sum(t(A)[i,k] * A[k,j]) =
sum(A[k,i] * A[k,j])
All of the products in the sum are either 0 or 1.
If both A[k,i]=1 and A[k,j]=1, the product is 1,
otherwise it is zero. So (t(A)%*%A)[i,j] is equal to the
number of different k's for which both A[k,i]=1 and
A[k,j]=1. But A[k,i]=1 means k is a neighbor of i
and A[k,j]=1 means k is a neighbor of j, so
(t(A)%*%A)[i,j] is equal to the number of different k's
for which k is a neighbor of both i and j.
Let's try it out on your example. In order to make the results
reproducible, I set the random.seed.
library(igraph)
## For reproducibility
set.seed(1492)
# create an adj. matrix
adjm <- matrix(sample(0:1, 100, replace=TRUE, prob=c(0.6,0.4)), nc=10)
# set diagonal element to 0
diag(adjm) <- 0
# making it symmetric
adjm[lower.tri(adjm)] = t(adjm)[lower.tri(adjm)]
Shared = t(adjm) %*% adjm
g = graph_from_adjacency_matrix(adjm, mode = "undirected")
plot(g)
Notice for example that Shared[1,4] = 4.
That is because nodes 1 and 4 have four shared neighbors,
Nodes 2,3,6 and 9. Shared[5,7]=0 because nodes 5 and 7
have no neighbors in common.
I think #G5W's solution is super concise already, highly recommended!
Below is a graph theory way to solve it, maybe not that efficient:
> nb <- neighborhood(g,mindist = 1)
> outer(nb, nb, FUN = Vectorize(function(a, b) length(intersect(a, b))))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 6 1 1 4 2 2 2 5 3 1
[2,] 1 3 2 0 1 3 0 1 2 1
[3,] 1 2 4 1 2 4 1 1 3 3
[4,] 4 0 1 4 2 1 1 3 2 1
[5,] 2 1 2 2 4 2 0 1 3 2
[6,] 2 3 4 1 2 5 1 2 3 3
[7,] 2 0 1 1 0 1 2 2 1 1
[8,] 5 1 1 3 1 2 2 5 3 1
[9,] 3 2 3 2 3 3 1 3 7 3
[10,] 1 1 3 1 2 3 1 1 3 4
> t(adjm) %*% adjm
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 6 1 1 4 2 2 2 5 3 1
[2,] 1 3 2 0 1 3 0 1 2 1
[3,] 1 2 4 1 2 4 1 1 3 3
[4,] 4 0 1 4 2 1 1 3 2 1
[5,] 2 1 2 2 4 2 0 1 3 2
[6,] 2 3 4 1 2 5 1 2 3 3
[7,] 2 0 1 1 0 1 2 2 1 1
[8,] 5 1 1 3 1 2 2 5 3 1
[9,] 3 2 3 2 3 3 1 3 7 3
[10,] 1 1 3 1 2 3 1 1 3 4
If the graph is undirected, then the matrix of the number of shared neighbours is A.A, where I used . to denote the matrix product. As others note, the correct operator in R is %*%. Transposition is not necessary, since in the undirected case, the adjacency matrix is symmetric: A' = A.
If the graph is directed, let's assume that A_{ij} denotes the number of connections from i to j (this is igraph's interpretation).
Then the i,j element of A'.A gives the number of nodes that point to both i and j (i <- v -> j), and A.A' gives the number of nodes that both i and j point to (i -> v <- j). These quantities are sometimes called cocitation and bibliographic coupling, respectively, and can be computed using cocitation() and bibcoupling() in igraph. In the undirected case, both of these functions return the same, thus you may use either.

Frequency/Contingency table along 1 dimension in R

I'm trying to count co-occurrences along a single dimension. It's somewhat similar to win/loss, dominance matrices, or frequency tables, (and spectrograms/raster plots) but without directionality and along 1 variable.
Here's an example of the data:
person response
1 a 1
2 a 2
3 a 4
4 b 1
5 b 2
6 c 2
7 c 4
8 d 4
9 d 3
The goal would be to get an n x n matrix as the one shown below (the NA's can also be the number of occurrences period):
[,1] [,2] [,3] [,4]
[1,] NA 2 0 1
[2,] - NA 0 2
[3,] - - NA 1
[4,] - - - NA
How can I convert the long data into a matrix in R? (without manual counting).
What is this type of metric is called? It's not a typical 'contingency' table.
After the table is created, what's the best way to plot the resulting matrix with colors denoting the count/frequency?
Test this
r1 = sort(unique(df1$response))
r2 = split(df1$response, df1$person)
ans = sapply(seq_along(r1), function(i)
rowSums(sapply(r2, function(x) (r1[i] %in% x) * (r1 %in% x))))
diag(ans) = NA
ans
# [,1] [,2] [,3] [,4]
#[1,] NA 2 0 1
#[2,] 2 NA 0 2
#[3,] 0 0 NA 1
#[4,] 1 2 1 NA

fill in a vector with intgers with respect to constraints

I'm using r and
I want to fill a 8 lenght dimension vector/table with integer numbers form 1 to 4 with respect to the conditions below:
vector [i]<= vector[i+1]
all integrs should be present
example:
1 1 1 1 2 2 3 4 may be a solution
1 2 1 1 2 3 3 4 isn't a solution to my problem
I am wondering also if there is a way to list all solutions
To get all solutions, reserve four slots for the numbers 1:4 (since every number must appear at least once), and consider all possible length-4 sequences of 1:4 to fill the remaining slots. Sorting and removing duplicates leaves you with 35 non-decreasing sequences:
# The sequences will be the rows of a matrix. First, the 'reserved' slots:
reserved = matrix(1:4, 256, 4, byrow=TRUE)
# Add all combinations of 1:4 to fill the remaining four slots:
result = cbind(reserved,
unname(as.matrix(expand.grid(1:4, 1:4, 1:4, 1:4))) )
# Now simply sort and de-duplicate along rows:
result = t(apply(result, 1, sort))
result = unique(result)
> head(result)
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
# [1,] 1 1 1 1 1 2 3 4
# [2,] 1 1 1 1 2 2 3 4
# [3,] 1 1 1 1 2 3 3 4
# [4,] 1 1 1 1 2 3 4 4
# [5,] 1 1 1 1 2 2 3 4
# [6,] 1 1 1 2 2 2 3 4

Creating a matrix of increasing concentric rings of numbers in R

I need to write a function in R that creates a matrix of increasing concentric rings of numbers. This function's argument is a number of layers. For example, if x = 3, matrix will look like following:
1 1 1 1 1
1 2 2 2 1
1 2 3 2 1
1 2 2 2 1
1 1 1 1 1
I have no idea how to do it. I would really appreciate any suggestions.
1) Try this:
x <- 3 # input
n <- 2*x-1
m <- diag(n)
x - pmax(abs(row(m) - x), abs(col(m) - x))
giving:
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 1 2 2 2 1
[3,] 1 2 3 2 1
[4,] 1 2 2 2 1
[5,] 1 1 1 1 1
2) A second approach is:
x <- 3 # input
n <- 2*x-1
mid <- pmin(1:n, n:1) # middle row/column
outer(mid, mid, pmin)
giving the same result as before.
3) yet another approach having some similarities to the prior two approaches is:
x <- 3 # input
n <- 2*x-1
Dist <- abs(seq_len(n) - x)
x - outer(Dist, Dist, pmax)
Note: The above gives the sample matrix shown in the question but the subject of the question says the rings should be increasing which may mean increasing from the center to the outside so if that is what is wanted then try this where m, mid and Dist are as before:
pmax(abs(row(m) - x), abs(col(m) - x)) + 1
or
x - outer(mid, mid, pmin) + 1
or
outer(Dist, Dist, pmax) + 1
Any of these give:
[,1] [,2] [,3] [,4] [,5]
[1,] 3 3 3 3 3
[2,] 3 2 2 2 3
[3,] 3 2 1 2 3
[4,] 3 2 2 2 3
[5,] 3 3 3 3 3
Try this:
x<-3
res<-matrix(nrow=2*x-1,ncol=2*x-1)
for (i in 1:x) res[i:(2*x-i),i:(2*x-i)]<-i
res
# [,1] [,2] [,3] [,4] [,5]
#[1,] 1 1 1 1 1
#[2,] 1 2 2 2 1
#[3,] 1 2 3 2 1
#[4,] 1 2 2 2 1
#[5,] 1 1 1 1 1
A recursive solution for kicks (odd n only)
f <- function(n) if (n == 1) 1 else `[<-`(matrix(1,n,n), 2:(n-1), 2:(n-1), 1+Recall(n-2))
f(5)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 1 1 1 1
# [2,] 1 2 2 2 1
# [3,] 1 2 3 2 1
# [4,] 1 2 2 2 1
# [5,] 1 1 1 1 1
Here's the logic, implement it yourself in R.
Create a matrix with number of rows and columns equal to 2*x-1 and
fill it with zeros and start traversing the array from (0,0) to
(2*x-2,2*x-2).
Now, at each cell, calculate the 'level' of the cell. The level of
the cell is the nearest distance of it from the four borders of
the matrix, i.e. min(i,j,2*x-2-i,2*x-2-j).
This 'level' value is the one to be put in the cell.

Applying outer to columns within a matrix

I have two matrices:
x
A B C
2 3 4
3 4 5
and y
D E
1 2
3 2
How can I subtract the combination of elements within columns? Giving me the following result:
AD AE BD BE CD CE
1 0 2 1 3 2
0 1 1 2 2 3
I have tried applying outer, but can't make it work with matrices. Would vectorizing a function be a solution? I have tried the code below, but it doesn't seem to work.
vecfun= Vectorize(fun)
fun=function(a,b)(a-b)
outer(x,y, vecfun)
Thanks in advance for any advice.
This doesn't use outer, but gets your intended result:
> do.call(cbind,lapply(1:ncol(x),function(i) x[,i]-y))
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 0 2 1 3 2
[2,] 0 1 1 2 2 3
Here's another way without loops/*apply family (assuming your matrices are x and y):
x[ , rep(seq_len(ncol(x)), each=ncol(y))] - y[, rep(seq_len(ncol(y)), ncol(x))]
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 0 2 1 3 2
[2,] 0 1 1 2 2 3
I'm not sure if it'll be faster, yet. But I thought it is an interesting approach. Also this would take twice the memory of your resulting matrix during computation.

Resources