How can I assign a value into a matrix based in a vector condition index. A working example is:
# Input:
r <- c(2, 1, 3)
m <- matrix(rep(0, 9), nrow = 3)
# Desired output
result <- matrix(c(0, 1, 0,
1, 0, 0,
0, 1, 0), nrow = 3)
result.
# I try with this notation but it does not work:
sapply(1:3, function(x)m[x, r[x]] <- 1)
We use row/column indexing to assign
m[cbind(seq_len(nrow(m)), r)] <- 1
Or using replace
replace(m, cbind(seq_len(nrow(m)), r), 1)
Related
The sample data is as follows
ID <- c(1, 2, 3)
O1D1 <- c(0, 0, 0)
O1D2 <- c(0, 0, 0)
O1D3 <- c(0, 10, 0)
O2D1 <- c(0, 0, 0)
O2D2 <- c(0, 0, 0)
O2D3 <- c(18, 0, 17)
O3D1 <- c(0, 9, 0)
O3D2 <- c(20, 1, 22)
O3D3 <- c(0, 0, 0)
x <- data.frame(ID, O1D1, O1D2, O1D3, O2D1, O2D2, O2D3, O3D1, O3D2, O3D3)
I created a new column with some conditional logic.
Say, the new column is n
x$n <- (x$O1D3 > 0 & x$O2D3 == 0)
> x$n
[1] FALSE TRUE FALSE
What I am looking to get instead is a column with values such as
> x$n
[1] 0 10 0
Or, in other words, the values of O1D3 should replace TRUE values in the n column and the FALSE values can be replaced with 0.
Thanks for your time and help.
I have made a matrix with values 1 and 0, and I want to check if there is one or more rows identical to (0, 0, 0, 0, 0, 0, 0, 0, 0, 0).
How can I do this?
Here's my code so far for making the matrix:
moeda <- c(0, 1)
n <- 100
casosTotais <- 0
casosFav <- 0
caras <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) ## the vector to compare with
matriz <- matrix(nrow = n, ncol = 10)
i <- 1
lin <- 1
col <- 1
while(i <= n * 10){
matriz[lin, col] <- sample(moeda,1)
if(col==10){
lin <- lin + 1
col <- col - 10
}
i <- i + 1
col <- col + 1
}
matriz
I will first assume a general caras with zeros and ones:
## a vector of TRUE/FALSE; TRUE means a row of `matriz` is identical to `caras`
comp <- colSums(abs(t(matriz) - caras)) == 0
Then if caras is a simply a vector of zeros:
## a vector of TRUE/FALSE; TRUE means a row of `matriz` only contains zeros
comp <- rowSums(matriz) == 0
If you want to summarize the comparison:
To know which rows of matriz are identical to caras, do which(comp).
To know if any row of matriz is identical to caras, do any(comp).
To know how many rows of matriz is identical to caras, do sum(comp).
Note: You can generate this random matrix using:
## an n x 10 random matrix of zeros and ones
matriz <- matrix(rbinom(n * 10, size = 1, prob = 0.5), ncol = 10)
I am attempting to replace a specific value in my list of matrices with each sequential value in a vector called one.to.two.s. This vector comprises a sequence of numbers running from 0.4 to 0.89 with steps of 0.01. From the code below, I would like to replace the value 2 in all matrices in the list by each consecutive value of one.to.two.s: the value 2 in the first matrix is replaced by the first value of one.to.two.s, the value 2 in the second matrix is replaced by the second value of one.to.two.s and so forth.
As an extension, I would like to be able repeat the one.to.two.s sequence if the vector had say length 50 and the list was say length 100. Below, I have a for loop which doesn't work, but I believe this could be handled with lapply somehow.
A <- lapply(1:50, function(x) # construct list of matrices
matrix(c(0, 0, 0, 0,
2, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 1), nrow = 4,ncol=4, byrow = TRUE))
Anew <-A
one.to.two.s <- c(seq(from = 0.40, to = 0.89,by=0.01))
for(t in 1:length(Anew)) {
Anew[[t]][2,1] <- one.to.two.s
}
Using an example one.to.two.s which is shorter than length(A), you could use rep with length.out to make it the correct length, and then Map over that vector and A to create Anew
one.to.two.s <- seq(from = 0.4, to = 0.8, by = 0.01)
Anew <- Map(function(A, x) {
A[2, 1] <- x
A
}, A, rep(one.to.two.s, length.out = length(A)))
Created on 2022-01-27 by the reprex package (v2.0.1)
You can try the following for loop if you have longer list than the vector
for(t in 1:length(Anew)) {
Anew[[t]][2,1] <- one.to.two.s[(t-1)%%length(one.to.two.s)+1]
}
I forgot to add [t] to the end of my replacement as well. Also can repeat a vector ahead of time.
for(t in 1:length(Anew)) {
Anew[[t]][2,1] <- one.to.two.s
}
instead becomes
for(t in 1:length(Anew)) {
Anew[[t]][2,1] <- one.to.two.s[t]
}
I believe this is what you are looking for. In this example, the list consists of 105 matrices.
# use replicate() instead of lapply()
B <- 50L
A <- replicate(B*2.1,
matrix(c(0, 0, 0, 0,
2, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 1), nrow = 4,ncol=4, byrow = TRUE),
simplify = FALSE)
Anew <- A
one.to.two.s <- seq(from = 0.40, to = 0.89, by = 0.01)
# loop over all elements in Anew
for (t in seq_along(Anew)) {
Anew[[t]][2,1] <- one.to.two.s[
seq_len(length(Anew) + 2L) %% (length(one.to.two.s) + 1L)
][t]
}
# > head(sapply(Anew, '[', 2))
# [1] 0.40 0.41 0.42 0.43 0.44 0.45
# > tail(sapply(Anew, '[', 2))
# [1] 0.89 0.40 0.41 0.42 0.43 0.44
I'm implementing the Jacobi iterative method to solve linear systems Ax = b
I have the following code:
data.a <- c(3, -1, 1, 3, 6, 2, 3, 3, 7)
A <- matrix(data.a, nrow = 3, ncol = 3, byrow = TRUE)
b <- c(1, 0, 4)
Xo <- c(0,0,0)
X <- c(0, 0, 0)
#A is the matrix:
#3 -1 1
#3 6 2
#3 3 7
#b is the column vector:
#[1, 0, 4]
#and Xo is the previous X computed
for(i in 1:nrow(A)){
sum = 0
for(j in 1:ncol(A)){
if(j != i){
sum = sum + A[i,j]*Xo[j]
}
}
X[i] = -(1/A[i,i])*(sum - b[i])
}
The thing is, because I only multiply and sum up the values A[i][j]*Xo[j] for j != i
I am using nested for-loops and use the auxiliar variable sum.
My question is: Could I use something like
A[i,] %*% Xo
to compute the values of the sum without the nested-for loops?
edit: I found a solution
X[i] = -(1/A[i,i])*(A[i,]%*%Xo - A[i,i]*Xo[i] - b[i])
# I subtracted the term A[i,i]*Xo[i] from the product A*Xo
You can even remove the first loop by making a matrix R, whose elements are equal to A except that diagonal elements are zeros.
update <- function(x, A, b) {
D <- diag(diag(A))
R <- A - D
sums <- R %*% x
x <- (b - sums) / diag(D)
x
}
data.a <- c(3, -1, 1, 3, 6, 2, 3, 3, 7)
A <- matrix(data.a, nrow = 3, ncol = 3, byrow = TRUE)
b <- c(1, 0, 4)
x <- c(0, 0, 0)
for (i in 1:100) x <- update(x, A, b)
x
# verify the answer is correct
solve(A, b)
I have the following code:
beta <- c(1, 2, 3)
X1 <- matrix(c(1, 1, 1, 1,
0, 1, 0, 1,
0, 0, 1, 1),
nrow = 4,
ncol = 3)
Z1 <- matrix(c(1, 1, 1, 1,
0, 1, 0, 1),
nrow = 4,
ncol = 2)
Z2 <- matrix(c(1, 1, 1, 1,
0, 1, 0, 1),
nrow = 4,
ncol = 2)
library(MASS)
S1 <- mvrnorm(70, mu = c(0,0), Sigma = matrix(c(10, 3, 3, 2), ncol = 2))
S2 <- mvrnorm(40, mu = c(0,0), Sigma = matrix(c(10, 4, 4, 2), ncol = 2))
z <- list()
y <- list()
for(j in 1:dim(S1)[1]){
for(i in 1:dim(S2)[1]){
z[[i]] <- X1 %*% beta+Z1 %*% S1[j,]+Z2 %*% S2[i,]+matrix(rnorm(4, mean = 0 , sd = 0.27), nrow = 4)
Z <- unname(do.call(rbind, z))
}
y[[j]] <- Z
Y <- unname(do.call(rbind, y))
}
X1 is a 4x3, Z1 and Z2 are 4x2 matrices. So everytime X1 %*% beta+X2 %*% S1[j,]+X2 %*% S2[i,]+matrix(rnorm(4, mean = 0 , sd = sigma), nrow = 4) is called it outputs a 4x1 matrix. So far I store all these values in the inner and outer loop in two lists and then call rbind() to transform them into a matrix. Is there a way to directly store them in matrices?
You can avoid using lists if you rely on the apply functions and on vector recycling. I broke down your equation into its parts. (I hope I interpreted it accurately!)
Mb <- as.vector(X1 %*% beta)
M1 <- apply(S1,1,function(x) Z1 %*% x )
M2 <- apply(S2,1,function(x) Z2 %*% x ) + Mb
Mout <- apply(M1,2,function(x) M2 + as.vector(x))
as.vector(Mout) + rnorm(length(Mout), mean = 0 , sd = 0.27)
because the random numbers are added after the matrix multiplication (ie are not involved in any calculation), you can just put them in on the end.
Also note that you can't add a smaller matrix to a larger one, but if you make it a vector first then R will recycle it as necessary. So when Mb (a vector of length 4) is added to a matrix with 4 rows and n columns, it is recycled n times.