I have a 7000 X 7000 matrix in R. For example purpose I will use a smaller matrix as following:-
a <- matrix(c(0:-9, 1:-8, 2:-7, 3:-6, 4:-5, 5:-4, 6:-3, 7:-2, 8:-1, 9:0),
byrow = TRUE, ncol = 10, nrow = 10)
I want to create a new matrix which has values equal to 1 where the absolute values in matrix a are between the closed interval of 2 and 5. And rest all other values equal to zero.
This would make the following matrix:-
b <- matrix(c(0,0,1,1,1,1,0,0,0,0
0,0,0,1,1,1,1,0,0,0
1,0,0,0,1,1,1,1,0,0
1,1,0,0,0,1,1,1,1,0
1,1,1,0,0,0,1,1,1,1
1,1,1,1,0,0,0,1,1,1
0,1,1,1,1,0,0,0,1,1
0,0,1,1,1,1,0,0,0,1
0,0,0,1,1,1,1,0,0,0
0,0,0,0,1,1,1,1,0,0),
byrow = TRUE, ncol = 10, nrow = 10)
I can do this using for loop, but I just want to know if there is a much better and effcient solution to do this.
Thanks in advance.
You can just write down the comparison. It gives you a logical matrix and you can then use unary + to turn the result into an integer matrix.
+(abs(a) >= 2 & abs(a) <= 5)
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,] 0 0 1 1 1 1 0 0 0 0
# [2,] 0 0 0 1 1 1 1 0 0 0
# [3,] 1 0 0 0 1 1 1 1 0 0
# [4,] 1 1 0 0 0 1 1 1 1 0
# [5,] 1 1 1 0 0 0 1 1 1 1
# [6,] 1 1 1 1 0 0 0 1 1 1
# [7,] 0 1 1 1 1 0 0 0 1 1
# [8,] 0 0 1 1 1 1 0 0 0 1
# [9,] 0 0 0 1 1 1 1 0 0 0
#[10,] 0 0 0 0 1 1 1 1 0 0
Perhaps you can try
> +((abs(a) - 2) * (abs(a) - 5) <= 0)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 0 0 1 1 1 1 0 0 0 0
[2,] 0 0 0 1 1 1 1 0 0 0
[3,] 1 0 0 0 1 1 1 1 0 0
[4,] 1 1 0 0 0 1 1 1 1 0
[5,] 1 1 1 0 0 0 1 1 1 1
[6,] 1 1 1 1 0 0 0 1 1 1
[7,] 0 1 1 1 1 0 0 0 1 1
[8,] 0 0 1 1 1 1 0 0 0 1
[9,] 0 0 0 1 1 1 1 0 0 0
[10,] 0 0 0 0 1 1 1 1 0 0
Related
This question already has an answer here:
Set diagonal of a matrix to zero in R
(1 answer)
Closed 2 years ago.
I tried using the rbern function in R but I realized that the diagonal entries are not all 0's.
This would be a possible way:
m <- 10
n <- 10
mat <- matrix(sample(0:1,m*n, replace=TRUE),m,n)
diag(mat) <- 0
#> mat
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
# [1,] 0 1 1 0 1 0 0 0 1 0
# [2,] 1 0 1 1 0 0 1 0 0 1
# [3,] 0 0 0 1 0 1 0 0 1 0
# [4,] 0 1 0 0 0 0 0 0 1 0
# [5,] 0 1 1 1 0 0 1 1 0 0
# [6,] 1 0 1 0 1 0 0 0 1 0
# [7,] 1 1 1 0 0 0 0 0 1 1
# [8,] 1 0 1 1 1 1 1 0 1 1
# [9,] 1 1 1 1 1 1 0 0 0 1
#[10,] 1 0 1 0 1 0 0 0 1 0
Here is Matlab code to form the matrix of logical values of '0' and '1'
A=[1 2 3 4 5 6 7 8 9 10 ];
N = numel(A);
step = 2; % Set this to however many zeros you want to add each column
index = N:-step:1;
val = (1:N+step).' <= index;
Which result in
val=
1 1 1 1 1
1 1 1 1 1
1 1 1 1 0
1 1 1 1 0
1 1 1 0 0
1 1 1 0 0
1 1 0 0 0
1 1 0 0 0
1 0 0 0 0
1 0 0 0 0
0 0 0 0 0
0 0 0 0 0
How to do same task in r ,particularly val = (1:N+step).' <= indexthis step?
One option is
i <- seq_len(ncol(m1))
sapply(rev(i), function(.i) {
m1[,.i][sequence(.i *2)] <- 1
m1[,.i]
})
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 1 1 1 1
# [2,] 1 1 1 1 1
# [3,] 1 1 1 1 0
# [4,] 1 1 1 1 0
# [5,] 1 1 1 0 0
# [6,] 1 1 1 0 0
# [7,] 1 1 0 0 0
# [8,] 1 1 0 0 0
# [9,] 1 0 0 0 0
#[10,] 1 0 0 0 0
#[11,] 0 0 0 0 0
#[12,] 0 0 0 0 0
Or vectorize it
i1 <- rep(i, rev(2*i))
m1[cbind(ave(i1, i1, FUN = seq_along), i1)] <- 1
m1
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 1 1 1 1
# [2,] 1 1 1 1 1
# [3,] 1 1 1 1 0
# [4,] 1 1 1 1 0
# [5,] 1 1 1 0 0
# [6,] 1 1 1 0 0
# [7,] 1 1 0 0 0
# [8,] 1 1 0 0 0
# [9,] 1 0 0 0 0
#[10,] 1 0 0 0 0
#[11,] 0 0 0 0 0
#[12,] 0 0 0 0 0
Or another option without creating a matrix beforehand
n <- 5
i1 <- seq(10, 2, by = -2)
r1 <- c(rbind(i1, rev(i1)))
matrix(rep(rep(c(1, 0), n), r1), ncol = n)
# [,1] [,2] [,3] [,4] [,5]
# [1,] 1 1 1 1 1
# [2,] 1 1 1 1 1
# [3,] 1 1 1 1 0
# [4,] 1 1 1 1 0
# [5,] 1 1 1 0 0
# [6,] 1 1 1 0 0
# [7,] 1 1 0 0 0
# [8,] 1 1 0 0 0
# [9,] 1 0 0 0 0
#[10,] 1 0 0 0 0
#[11,] 0 0 0 0 0
#[12,] 0 0 0 0 0
data
m1 <- matrix(0, 12, 5)
I want to make all combinations of my Matrix.
Ex. a binary 5 X 5 matrix where I only have two 1 rows (see below)
Com 1:
1 1 0 0 0
1 1 0 0 0
1 1 0 0 0
1 1 0 0 0
1 1 0 0 0
Com 2:
1 0 1 0 0
1 1 0 0 0
1 1 0 0 0
1 1 0 0 0
1 1 0 0 0
.
.
.
Com ?:
0 0 0 1 1
0 0 0 1 1
0 0 0 1 1
0 0 0 1 1
0 0 0 1 1
I tried using Combination package in R, but couldn't find a solution.
Using RcppAlgos (I am the author) we can accomplish this with 2 calls. It's quite fast as well:
library(tictoc)
library(RcppAlgos)
tic("RcppAlgos solution")
## First we generate the permutations of the multiset c(1, 1, 0, 0, 0)
binPerms <- permuteGeneral(1:0, 5, freqs = c(2, 3))
## Now we generate the permutations with repetition choose 5
## and select the rows from binPerms above
allMatrices <- permuteGeneral(1:nrow(binPerms), 5,
repetition = TRUE,
FUN = function(x) {
binPerms[x, ]
})
toc()
RcppAlgos solution: 0.108 sec elapsed
Here is the output:
allMatrices[1:3]
[[1]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 0 0 0
[2,] 1 1 0 0 0
[3,] 1 1 0 0 0
[4,] 1 1 0 0 0
[5,] 1 1 0 0 0
[[2]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 0 0 0
[2,] 1 1 0 0 0
[3,] 1 1 0 0 0
[4,] 1 1 0 0 0
[5,] 1 0 1 0 0
[[3]]
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 0 0 0
[2,] 1 1 0 0 0
[3,] 1 1 0 0 0
[4,] 1 1 0 0 0
[5,] 1 0 0 1 0
len <- length(allMatrices)
len
[1] 100000
allMatrices[(len - 2):len]
[[1]]
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 1 1
[2,] 0 0 0 1 1
[3,] 0 0 0 1 1
[4,] 0 0 0 1 1
[5,] 0 0 1 1 0
[[2]]
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 1 1
[2,] 0 0 0 1 1
[3,] 0 0 0 1 1
[4,] 0 0 0 1 1
[5,] 0 0 1 0 1
[[3]]
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 1 1
[2,] 0 0 0 1 1
[3,] 0 0 0 1 1
[4,] 0 0 0 1 1
[5,] 0 0 0 1 1
The code I've written below worked for me. A list of 100,000 5x5 matrices. Each of the rows has two places set to 1.
n <- 5 # No of columns
k <- 2 # No. of ones
m <- 5 # No of rows in matrix
nck <- combn(1:n,k,simplify = F)
possible_rows <-lapply(nck,function(x){
arr <- numeric(n)
arr[x] <- 1
matrix(arr,nrow=1)
})
mat_list <- possible_rows
for(i in 1:(m-1)){
list_of_lists <- lapply(mat_list,function(x){
lapply(possible_rows,function(y){
rbind(x,y)
})
})
mat_list <- Reduce(c,list_of_lists)
print(c(i,length(mat_list)))
}
how can i make a black and white heatmap of a given matrix that consists of zeros and ones where the zeros are depicted with black and the ones with white using the image function in r?
Make a matrix:
set.seed(42)
mat <- matrix(round(runif(100)), ncol = 10)
mat
#> [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#> [1,] 1 0 1 1 0 0 1 0 1 1
#> [2,] 1 1 0 1 0 0 1 0 0 0
#> [3,] 0 1 1 0 0 0 1 0 0 0
#> [4,] 1 0 1 1 1 1 1 0 1 1
#> [5,] 1 0 0 0 0 0 1 0 1 1
#> [6,] 1 1 1 1 1 1 0 1 1 1
#> [7,] 1 1 0 0 1 1 0 0 0 0
#> [8,] 0 0 1 0 1 0 1 0 0 1
#> [9,] 1 0 0 1 1 0 1 1 0 1
#> [10,] 1 1 1 1 1 1 0 0 0 1
Plot it:
image(t(mat[nrow(mat):1,]), col = c("black", "white"))
t() and nrow(mat):1 are used to reorder the matrix so the image of the matrix matches up with the printed matrix.
If e.g. |S| = 8, how can i get the 256 x 8 matrix with rows of the form:
> sample(c(0,1),8,replace=T)
[1] 1 0 0 1 1 1 0 0
maybe this helps:
library(e1071)
bincombinations(8)
Here is a much faster (and arguably cleaner) version of bincombinations:
fast.bincombinations <- function(p)
vapply(X = seq_len(p),
FUN = function(i)rep(rep(0:1, each = 2^(p-i)), times = 2^(i-1)),
FUN.VALUE = integer(2^(p)))
system.time(fast.bincombinations(24))
# user system elapsed
# 2.967 1.056 3.995
system.time(bincombinations(24))
# user system elapsed
# 11.144 12.111 53.687
Let's also mention that bincombinations outputs a matrix of numerics, which is bad design IMHO.
You could do this:
s = 8 # <-- |s| = 8
pset <- t(sapply(0:(2^s-1),intToBits))[,1:s] # <-- a matrix of 256x8 raws
pset <- apply(pset ,2,as.integer) # <-- raws to integers
Results:
> head(pset)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 0 0 0 0 0 0 0 0
[2,] 1 0 0 0 0 0 0 0
[3,] 0 1 0 0 0 0 0 0
[4,] 1 1 0 0 0 0 0 0
[5,] 0 0 1 0 0 0 0 0
[6,] 1 0 1 0 0 0 0 0
> tail(pset)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[251,] 0 1 0 1 1 1 1 1
[252,] 1 1 0 1 1 1 1 1
[253,] 0 0 1 1 1 1 1 1
[254,] 1 0 1 1 1 1 1 1
[255,] 0 1 1 1 1 1 1 1
[256,] 1 1 1 1 1 1 1 1
Here's another way:
s = 8;
res <- sapply(0:(s-1),function(x)rep(c(rep(0,2^x),rep(1,2^x)),2^(s-x-1)))