Changing Values in a Matrix based on a condition - r

So I have seen many posts about altering all values in a matrix less than a certain number equal to zero with some simple indexing of the matrix. But I think what I have is a little more advanced and I am having some trouble so hopefully you guys can help out. Here is the code I am working with:
x <- (1:5)
y <- c(0,10,0,0,8)
n <- 12
mat <- t(sapply(y, function(test) pmax(seq(test, (test-n+1), -1), 0) ))
mat
This produces:
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 0 0 0 0 0 0 0 0 0 0 0 0
[2,] 10 9 8 7 6 5 4 3 2 1 0 0
[3,] 0 0 0 0 0 0 0 0 0 0 0 0
[4,] 0 0 0 0 0 0 0 0 0 0 0 0
[5,] 8 7 6 5 4 3 2 1 0 0 0 0
xmat <- replicate(ncol(mat),x)
Then I wanted to find which y does not equal to zero and then replace the values in xmat to zero until mat equals zero and then change the value to the x value. So below is what I currently have.
CountTest <- which(y != 0)
xmat[CountTest,] <- apply(xmat[CountTest,], 1, function(xu) ifelse(xu > 0, 0, xu))
xmat
This produces:
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 1 1 1 1 1 1 1 1 1 1 1 1
[2,] 0 0 0 0 0 0 0 0 0 0 0 0
[3,] 3 3 3 3 3 3 3 3 3 3 3 3
[4,] 4 4 4 4 4 4 4 4 4 4 4 4
[5,] 0 0 0 0 0 0 0 0 0 0 0 0
The desired output is:
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,] 1 1 1 1 1 1 1 1 1 1 1 1
[2,] 0 0 0 0 0 0 0 0 0 0 2 2
[3,] 3 3 3 3 3 3 3 3 3 3 3 3
[4,] 4 4 4 4 4 4 4 4 4 4 4 4
[5,] 0 0 0 0 0 0 0 0 5 5 5 5

You could try
> xmat*(mat==0)
# [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
#[1,] 1 1 1 1 1 1 1 1 1 1 1 1
#[2,] 0 0 0 0 0 0 0 0 0 0 2 2
#[3,] 3 3 3 3 3 3 3 3 3 3 3 3
#[4,] 4 4 4 4 4 4 4 4 4 4 4 4
#[5,] 0 0 0 0 0 0 0 0 5 5 5 5

Related

Transform Identity Matrix

I have identity matrix which can be generated via diag(5)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 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
I want to convert it to the matrix wherein series starts after 1. For example 1st column, values 1 through 5. Second column - values 1 through 4.
Desired Output
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 2 1 0 0 0
[3,] 3 2 1 0 0
[4,] 4 3 2 1 0
[5,] 5 4 3 2 1
Try the code below (given m <- diag(5))
> (row(m) - col(m) + 1)*lower.tri(m,diag = TRUE)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 2 1 0 0 0
[3,] 3 2 1 0 0
[4,] 4 3 2 1 0
[5,] 5 4 3 2 1
Another option is using apply + cumsum
> apply(lower.tri(m, diag = TRUE), 2, cumsum)
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 2 1 0 0 0
[3,] 3 2 1 0 0
[4,] 4 3 2 1 0
[5,] 5 4 3 2 1
1) If d <- diag(5) is the identity matrix then:
pmax(row(d) - col(d) + 1, 0)
giving:
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 2 1 0 0 0
[3,] 3 2 1 0 0
[4,] 4 3 2 1 0
[5,] 5 4 3 2 1
2) This alternative is slightly longer (though still a one-liner) but also works if the columns of d are rearranged and/or some columns are missing. For example,
dd <- d[, 4:1] # test data
pmax(outer(1:nrow(dd) + 1, max.col(t(dd)), `-`), 0)
giving the same result for d and this for dd:
[,1] [,2] [,3] [,4]
[1,] 0 0 0 1
[2,] 0 0 1 2
[3,] 0 1 2 3
[4,] 1 2 3 4
[5,] 2 3 4 5
A solution based on nested cumsum:
n <- 5
m <- diag(n)
apply(m, 2, function(x) cumsum(cumsum(x)))
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] 1 0 0 0 0
#> [2,] 2 1 0 0 0
#> [3,] 3 2 1 0 0
#> [4,] 4 3 2 1 0
#> [5,] 5 4 3 2 1
One option could be:
x <- 1:5
embed(c(rep(0, length(x) - 1), x), length(x))
[,1] [,2] [,3] [,4] [,5]
[1,] 1 0 0 0 0
[2,] 2 1 0 0 0
[3,] 3 2 1 0 0
[4,] 4 3 2 1 0
[5,] 5 4 3 2 1

Filter by a column value in a 3D matrix in R

Edit: I've included a reproducible example.
I am trying to do some simple operation in one of my matrices. My matrices are 3D arrays which contain capture-recapture data.
Rows are individuals
Columns from 1 to 7 are sampling occasions (years)
Column 8 sex of the individual: 1 males 2 females
libray(abind)
CH <- array(c(1,0,1,1,1,1,0), dim = c(5,7,10))
sex <- c(1,1,2,2,1)
CH_with_sex <- abind(CH, array(sex, replace(dim(CH), 2, 1)), along = 2)
CH_with_sex
, , 1
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 0 0 1 1 1
[2,] 0 0 1 1 1 1 1 1
[3,] 1 1 1 1 0 0 1 2
[4,] 1 0 0 1 1 1 1 2
[5,] 1 1 1 1 1 0 0 1
, , 2
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 0 0 1 1 1
[2,] 0 0 1 1 1 1 1 1
[3,] 1 1 1 1 0 0 1 2
[4,] 1 0 0 1 1 1 1 2
[5,] 1 1 1 1 1 0 0 1
dim(CH_with_sex)
[1] 5 8 10
My aim is to separate males and females from this 3D array and have 2 different arrays: one for the males and another one for females. I thought of making it by filtering for the column 8 but I can't find the way to do it. I end up breaking or losing the matrix structure. Any advice?
My desired output would be this for males:
, , 1
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 0 0 1 1 1
[2,] 0 0 1 1 1 1 1 1
[3,] 1 1 1 1 1 0 0 1
, , 2
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 0 0 1 1 1
[2,] 0 0 1 1 1 1 1 1
[3,] 1 1 1 1 1 0 0 1
And this for females:
, , 1
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 1 0 0 1 2
[2,] 1 0 0 1 1 1 1 2
, , 2
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 1 1 1 1 0 0 1 2
[2,] 1 0 0 1 1 1 1 2
Here, x is your three-dimensional array CH_with_sex, and l is a list of two three-dimensional arrays splitting x by sex.
d <- dim(x)
f <- function(i) x[i, , , drop = FALSE]
l <- c(tapply(seq_len(d[1L]), x[, d[2L], 1L], f, simplify = FALSE))
dim(l[[1]])
## [1] 3 8 10
dim(l[[2]])
## [1] 2 8 10

can someone please break down 4th line of code for me? This is in R

r=5 # 5 blocks
t=10 # 10 treatments
RCB=matrix(0, r, t)
for(i in 1:r)RCB[i,]=sample(1:t)
#rownames(RCB)=c("Block","Treatment")
data.frame(RCB)
can someone please break down the 4th line of code for me? This is in R. The author is trying to create an RCBD data set, I didn't write this code. I'm trying to learn for loops
Here is my explanation of the fourth line.
for(i in 1:r) This specifies a for loop that iterates from 1 to r. In this example, r is 5. : is a way to specify a sequence from one integer to another, so 1:r is the same as c(1, 2, 3, 4, 5).
RCB[i, ] means for each iteration, access to row i in the matrix. There are five rows in RCB. The for loop will access to each row one by one.
= is the assign operator in R. We can also use <-.
sample(1:t) takes a random sample from 1:t. In this example, it is one number from 1 to 10. The output would store to that row in RCB.
Before you run line 4, the RCB matrix is as follows.
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 0 0 0 0 0 0 0 0 0 0
[2,] 0 0 0 0 0 0 0 0 0 0
[3,] 0 0 0 0 0 0 0 0 0 0
[4,] 0 0 0 0 0 0 0 0 0 0
[5,] 0 0 0 0 0 0 0 0 0 0
After line 4, it becomes something like this.
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 5 7 6 8 2 1 9 3 10 4
[2,] 5 3 2 8 9 4 7 1 6 10
[3,] 6 9 10 3 8 1 7 5 4 2
[4,] 2 1 5 9 4 3 10 7 6 8
[5,] 4 6 5 3 10 1 9 8 7 2
All rows are populated with random numbers from 1 to 10.

How to find the smallest values of list of matrices by column

Suppose I have a list of matrices. Suppose further that I would like to find the smallest value across each value of the matrices. For example,
y <- c(3,2,4,5,6, 4,5,5,6,7)
x[lower.tri(x,diag=F)] <- y
> x
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 0 0
[2,] 3 0 0 0 0
[3,] 2 6 0 0 0
[4,] 4 4 5 0 0
[5,] 5 5 6 7 0
k <- c(1,4,5,2,5,-4,4,4,4,5)
z[lower.tri(z,diag=F)] <- k
> z
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 0 0
[2,] 1 0 0 0 0
[3,] 4 5 0 0 0
[4,] 5 -4 4 0 0
[5,] 2 4 4 5 0
d <- list(k, x)
The expected output:
dd <– matrix(0,5,5)
dd
[,1] [,2] [,3] [,4] [,5]
[1,] 0 0 0 0 0
[2,] 1 0 0 0 0
[3,] 2 5 0 0 0
[4,] 4 -4 4 0 0
[5,] 2 4 4 5 0
We could use pmin to get the corresponding min value for each element across the list
do.call(pmin, d)
# [,1] [,2] [,3] [,4] [,5]
#[1,] 0 0 0 0 0
#[2,] 1 0 0 0 0
#[3,] 2 5 0 0 0
#[4,] 4 -4 4 0 0
#[5,] 2 4 4 5 0
data
d <- list(z, x)

R add many columns by a function

I am trying to cut a number in layers by mean the next code:
X <- matrix(c(6,7,9,9,9,17,19,4,12,2,3,6,7,7),ncol=2)
layers <- c(5,10,15,20,25,30,35,40)
partitions <- function(u) {cbind(pmin(layers[1],u),t(diff(pmin(layers,u))))}
X <- cbind(X,lapply(X[,2], partitions))
The function returns an integer partitioned in the layers.
A = a1 + a2 + .... + a8
Example
A <- 19
partitions(A)
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,] 5 5 5 4 0 0 0 0
But the results does not have the matrix I need. The final matrix would be of 7 x (2 (cols from X) + 8 (num of layers in points))
[,1] [,2] [,3]
[1,] 6 Numeric,8 NULL
[2,] 7 Numeric,8 NULL
[3,] 9 Numeric,8 NULL
[4,] 9 Numeric,8 NULL
[5,] 9 Numeric,8 NULL
[6,] 17 Numeric,8 NULL
[7,] 19 Numeric,8 NULL
> dim(X)
[1] 7 3
I tried different forms and ever had errors of dimensions.
Regards
One of these two should be what you want
> rbind(t(X),sapply(X[,2], partitions))
[,1] [,2] [,3] [,4] [,5] [,6] [,7]
[1,] 6 7 9 9 9 17 19
[2,] 4 12 2 3 6 7 7
[3,] 4 5 2 3 5 5 5
[4,] 0 5 0 0 1 2 2
[5,] 0 2 0 0 0 0 0
[6,] 0 0 0 0 0 0 0
[7,] 0 0 0 0 0 0 0
[8,] 0 0 0 0 0 0 0
[9,] 0 0 0 0 0 0 0
[10,] 0 0 0 0 0 0 0
> cbind(X,t(sapply(X[,2], partitions)))
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] 6 4 4 0 0 0 0 0 0 0
[2,] 7 12 5 5 2 0 0 0 0 0
[3,] 9 2 2 0 0 0 0 0 0 0
[4,] 9 3 3 0 0 0 0 0 0 0
[5,] 9 6 5 1 0 0 0 0 0 0
[6,] 17 7 5 2 0 0 0 0 0 0
[7,] 19 7 5 2 0 0 0 0 0 0

Resources