Related
I have
F <- structure(c(0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0), .Dim = c(3L,
5L))
How can I remove from F the columns that have less than 2 consecutive zero?
Thx!
We may use rle to determine the consecutive values i.e. 0 and create a logical condition with lengths by looping over the column (apply, MARGIN = 2)
F[,!apply(F, 2, function(x) with(rle(!x),
any(lengths >= 2 & values))), drop = FALSE]
-output
[,1] [,2]
[1,] 0 0
[2,] 1 1
[3,] 1 1
If it is the opposite, just remove the !
F[,apply(F, 2, function(x) with(rle(!x),
any(lengths >= 2 & values))), drop = FALSE]
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 0 0 0
[3,] 0 0 0
A slightly different approach with rle applied over the columns:
F[, apply(F, 2, \(x) with(rle(x), any(lengths[values == 0] >= 2)))]
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 0 0 0
[3,] 0 0 0
Using pure base, no extra functions, as one-liner:
U = F[, apply((F[-1,]==0) & (F[-nrow(F),]==0), 2, any)]
Breakdown:
U = F[ # Select...
, # ...all the rows in the matrix...
apply( # ...that have...
(F[-nrow(F),]==0) & (F[-1,]==0), # ...one value = 0 and the next value = 0
2, # ...in columns (i.e. 2nd dimension)....
any # ...anywhere in the column.
)
]
I am trying to add two matrices with different dimension in R. Ideally, the system should equate two matrices adding missing rows/columns, filled with zeros. For instance, if we have one matrix with 1:4 rows and another with 1:5 rows and their number of columns is identical. So to add the two matrices we need to add to the first matrix the fifth row full of zeros.
Could you please help.
#Matrix1
a11<-matrix(c(419371623, 10990236, 29346292, 0, 0, 39386246.52, 0, 0,0 ,0,0, 0, 0, 0, 30174248.77,0, 27839925.91, 0 ,0 ,112921829.5),4,5,dimnames = list(c(1,2,3,5),c(1,2,3,4,5)),byrow=TRUE)
#Matrix 2
a22<-matrix(c(853624485, 0, 766111,0, 0, 20240075.89 ,0, 4839059.2,0, 2062687.122 ,0, 0,0 ,0 ,0 ,7282484.458,0, 18738621.67 ,0 ,0),5,4,byrow=TRUE, list(c(1:5),c(1:4)))
#Expected Result:
res<- matrix(c(1272996108, 10990236, 30112402.72, 0, 0,
39386247, 20240075.89, 0, 48390599.21, 0,
0, 2062687.122 ,0, 0, 30174249,
0, 27839926, 0, 7282484.458, 112921830,
0, 18738622, 0, 0, 0), 5, 5, byrow=TRUE, dimnames = list(1:5,1:5)
You could write your own function to perform this:
`%+%` <- function(a, b){
i <- dim(a)
j <- dim(b)
out <- pmax(i,j)
valid <- pmin(i,j)
result <- matrix(0, out[1], out[2])
v_row <- seq(valid[1])
v_col <- seq(valid[2])
result[v_row, v_col] <- a[v_row, v_col] + b[v_row, v_col]
ind1 <- which(result[seq(i[1]), seq(i[2])] == 0 & a!=0, TRUE)
result[ind1] <- a[ind1]
ind2 <- which(result[seq(j[1]), seq(j[2])] == 0 & b!=0, TRUE)
result[ind2] <- b[ind2]
result
}
a11%+%a22
[,1] [,2] [,3] [,4] [,5]
[1,] 1272996108 10990236 30112403 0 0
[2,] 39386247 20240076 0 4839059 0
[3,] 0 2062687 0 0 30174249
[4,] 0 27839926 0 7282484 112921830
[5,] 0 18738622 0 0 0
s1 <- matrix(1,3,5)
s2 <- matrix(2, 5,2)
s1
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 1 1 1 1 1
[3,] 1 1 1 1 1
s2
[,1] [,2]
[1,] 2 2
[2,] 2 2
[3,] 2 2
[4,] 2 2
[5,] 2 2
s1 %+% s2
[,1] [,2] [,3] [,4] [,5]
[1,] 3 3 1 1 1
[2,] 3 3 1 1 1
[3,] 3 3 1 1 1
[4,] 2 2 0 0 0
[5,] 2 2 0 0 0
Maybe there is a shorter/better way to make the dimension of both the matrix equal but here is one way.
n <- max(ncol(a11), ncol(a22))
m <- max(nrow(a11), nrow(a22))
if(m > ncol(a11)) a11 <- cbind(a11, matrix(0, ncol = m - ncol(a11), nrow = nrow(a11)))
if(m > ncol(a22)) a22 <- cbind(a22, matrix(0, ncol = m - ncol(a22), nrow = nrow(a22)))
if(n > nrow(a11)) a11 <- rbind(a11, matrix(0, ncol = ncol(a11), nrow = n - nrow(a11)))
if(n > nrow(a22)) a11 <- rbind(a11, matrix(0, ncol = ncol(a12), nrow = n - nrow(a22)))
Now a11 and a22 are of same dimension so you can add them :
a11 + a22
# 1 2 3 4 5
#1 1272996108 10990236 30112403 0 0
#2 39386247 20240076 0 4839059 0
#3 0 2062687 0 0 30174249
#5 0 27839926 0 7282484 112921830
# 0 18738622 0 0 0
After initializing res to zero, I am adding the matrices by indices.
Easily extendable to add more matrices.
# initilize res
res <- matrix(0, nrow = max(nrow(a11), nrow(a22)),
ncol = max(ncol(a11), ncol(a22)))
# index of a11
inds <- which(!is.na(a11), arr.ind = T)
res[inds] <- res[inds] + a11[inds]
# index of a22
inds <- which(!is.na(a22), arr.ind = T)
res[inds] <- res[inds] + a22[inds]
# repeat for a33 etc if there's more.
Results with a11 and a22
> res
[,1] [,2] [,3] [,4] [,5]
[1,] 1272996108 10990236 30112403 0 0
[2,] 39386247 20240076 0 4839059 0
[3,] 0 2062687 0 0 30174249
[4,] 0 27839926 0 7282484 112921830
[5,] 0 18738622 0 0 0
I am trying to create the following matrix A for n rows and n+1 columns. n will likely be around 20 or 30, but for the purpose of the question I put it at 4 and 5.
Here is what I have so far:
N <- 5 # n+1
n <- 4 # n
columns <- list()
# first column:
columns[1] <- c(-1, 1, rep(0, N-2))
# all other columns:
for(i in N:2) {
columns[i] <- c((rep(0, N-i), 1, -2, 1, rep(0, i-3)))
}
# combine into matrix:
A <- cbind(columns)
I keep getting the following error msg:
In columns[1] <- c(-1, 1, rep(0, N - 2)) :
number of items to replace is not a multiple of replacement length
And later
"for(i in N:2) {
columns[i] <- c((rep(0, N-i),"
}
Error: unexpected '}' in "}"
I guess you can try the for loop below to create your matrix A:
N <- 5
n <- 4
A <- matrix(0,n,N)
for (i in 1:nrow(A)) {
if (i == 1) {
A[i,1:2] <- c(-1,1)
} else {
A[i,i+(-1:1)] <- c(1,-2,1)
}
}
such that
> A
[,1] [,2] [,3] [,4] [,5]
[1,] -1 1 0 0 0
[2,] 1 -2 1 0 0
[3,] 0 1 -2 1 0
[4,] 0 0 1 -2 1
Another solution is to use outer, and this method would be faster and looks more compact than the for loop approach, i.e.,
A <- `diag<-`(replace(z<-abs(outer(1:n,1:N,"-")),!z %in% c(0,1),0),
c(-1,rep(-2,length(diag(z))-1)))
I thought this would be fast compared to the loop, but when I tested on a 5000x5001 example, the loop in ThomasIsCoding's answer was about 5x faster. Go with that one!
N = 5
n = N - 1
A = matrix(0, nrow = n, ncol = N)
delta = row(A) - col(A)
diag(A) = -2
A[delta %in% c(1, -1)] = 1
A[1, 1] = -1
A
# [,1] [,2] [,3] [,4] [,5]
# [1,] -1 1 0 0 0
# [2,] 1 -2 1 0 0
# [3,] 0 1 -2 1 0
# [4,] 0 0 1 -2 1
You could use data.table::shift to shift the vector c(1, -2, 1, 0) by all increments from -1 (backwards shift / lead by 1) to n - 1 (forward shift / lagged by n - 1) and then cbind all the shifted outputs together. The first-row first-column element doesn't follow this pattern so that's fixed at the end.
library(data.table)
out <- do.call(cbind, shift(c(1, -2, 1, 0), seq(-1, n - 1), fill = 0))
out[1, 1] <- -1
out
# [,1] [,2] [,3] [,4] [,5]
# [1,] -1 1 0 0 0
# [2,] 1 -2 1 0 0
# [3,] 0 1 -2 1 0
# [4,] 0 0 1 -2 1
I have a matrix with ID values at grid points and I have a vector containing some of those ID's. I would like to write a function so that for all the ID's contained in the vector, the corresponding ID in the matrix is set to 0.
For example:
ID <- matrix(c(2,3), nrow=2)
A <- matrix(c(0, 0, 2, 2, 0, 3,
1, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 4,
1, 0, 1, 0, 0, 4), nrow=4, byrow=TRUE)
I would like to transform my matrix A so that the 2's and 3 become 0.
I found a way to do this manually with the "if" function, setting conditions:
a <- nrow(A)
b <- ncol(A)
vide <- array(NaN, dim=c(a,b))
for (i in c(1:a)) {for (j in c(1:b)) {
if ( (A[i,j]==ID[1,1]) | (A[i,j]==ID[2,1]) ) {
vide[i,j]==0} else {vide[i,j]=A[i,j]}
}
}
vide[is.na(vide)] <- 0
But I would like to create an automatic function that will do this for all the ID's contained in the ID vector, regardless of the number of rows. Because I will then run this over many years and the ID matrix will not always have the same number of rows. Is there a way to do that ?
I also tried another way, to make R write the conditions in the "if" function by itself:
d <- nrow(ID)
Cond <- array(NaN, dim=c(d,1))
for (k in c(1:d)) {
Cond[k,1]=paste("(A[i,j]==ID[",k,",1]) ", sep="")
}
Cond <- t(Cond)
Cond <- paste(Cond,collapse="| ")
Cond <- noquote(Cond)
for (i in c(1:a)) {for (j in c(1:b)) {
if (Cond) {
vide[i,j]==0
} else {
vide[i,j]=A[i,j]
}
}
but the problem is that Cond is a character matrix and I get the error message "argument is not interpretable as logical".
I am a beginner in R so maybe there is an easier way to do what I would like to do ? I tried searching on Internet but never seemed to find something appropriate to my case. Thanks for your help!
How's this? The trick is to handle matrix is a vector. R will take care of the second dimension on the fly. What I do below is find where in A elements from ID appear and overwrite them with a zero.
> A
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0 0 2 2 0 3
[2,] 1 0 0 0 0 0
[3,] 0 1 0 0 0 4
[4,] 1 0 1 0 0 4
> A[A %in% ID] <- 0
> A
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0 0 0 0 0 0
[2,] 1 0 0 0 0 0
[3,] 0 1 0 0 0 4
[4,] 1 0 1 0 0 4
I use a r-matrix (for example [[0,0,0,1],[0,1,0,1],[1,0,0,0],[0,0,1,1]]) representing
a raster. I'd like to replace every value except 0 with its row index value. Is there something like
matrix[matrix==1] <- row_index
so that my result would look like [[0,0,0,1],[0,2,0,2],[3,0,0,0],[0,0,4,4]]?
I am using R 2.15.1 on a Mac (10.7.5) and RPY2 2.2.6 to start the R-Methods.
Or is there any other way to get reasonable results for statistical functions like histogram, chi_square etc.?
For a succinct, expressive solution, I'd be likely to use this:
m <- matrix(c(0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1),
nrow = 4, byrow = TRUE)
m[m!=0] <- row(m)[m!=0]
m
# [,1] [,2] [,3] [,4]
# [1,] 0 0 0 1
# [2,] 0 2 0 2
# [3,] 3 0 0 0
# [4,] 0 0 4 4
Hopefully all hell won't break loose for suggesting a for loop, but we'll see:
Here's your matrix
mymat <- matrix(c(0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1),
nrow = 4, byrow = TRUE)
mymat
# [,1] [,2] [,3] [,4]
# [1,] 0 0 0 1
# [2,] 0 1 0 1
# [3,] 1 0 0 0
# [4,] 0 0 1 1
Here's a for loop that uses basic subsetting to identify the cases you want to replace.
for (i in 1:nrow(mymat)) {
mymat[i, ][mymat[i, ] != 0] <- i
}
Here's the result.
mymat
# [,1] [,2] [,3] [,4]
# [1,] 0 0 0 1
# [2,] 0 2 0 2
# [3,] 3 0 0 0
# [4,] 0 0 4 4
Maybe I'm missing the point of your question, but how about
> m <- matrix(c(0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1),
+ nrow = 4, byrow = TRUE)
> m * 1:nrow(m)
[,1] [,2] [,3] [,4]
[1,] 0 0 0 1
[2,] 0 2 0 2
[3,] 3 0 0 0
[4,] 0 0 4 4
>
(ETA: R fills in matrices by column, and the itemwise product operator makes the two matrices involved conformant by replicating them column by column until they fit. The * operator here winds up multiplying each item by the row to which it belongs.)