Set values withing a range equal to 1 and rest to 0 - r

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

Random matrix with diagonal entries 0's and all other entries are 0's and 1's [duplicate]

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

How to form the matrix of logical '1' and '0' using two vectors and logical operators in r?

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)

R: Matrix Combination with specific number of values

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)))
}

Heatmap of a matrix of zeros and ones using image function in R

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.

Generate the powerset as a list of 0/1 selection vectors

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)))

Resources