Updating Loop of Markov Matrix: subscript out of boundaries - r

I am trying to multiply matrices. The values within the matrices represent probabilities that are different for each cycle. Therefore, I use loop for to update the values within the matrix. At the beginning it works fine, but then I get the feedback: subscript out of boundaries. The error message is showing my next values [4,] 210, 323, 467. Why are they not displayed at the bottom?
> initial_patient_distribtion <- c (1000,0,0)
> aaa <- c(1,0.7,0.6,0.5,0.4)
> bbb <- c(1, 0.2,0.3, 0.4, 0.5)
> ccc <- c(1, 0.1,0.1,0.1,0.1)
>
> cycle_patient_distribution_dasa_no2nd[1,] <-initial_patient_distribtion
> for (i in 2:length(aaa)){
+ trans_matrix_dasa_no2nd <- matrix (,nrow=3,ncol=3)
+ trans_matrix_dasa_no2nd[1,] <- c(aaa[i],bbb[i],ccc[i])
+ trans_matrix_dasa_no2nd[2,] <- c(0,0.5,0.5)
+ trans_matrix_dasa_no2nd[3,] <- c(0,0,1)
+
+ cycle_patient_distribution_dasa_no2nd[i,] <- cycle_patient_distribution_dasa_no2nd[i-1,]%*%(trans_matrix_dasa_no2nd)}
Error in `[<-`(`*tmp*`, i, , value = c(210, 323, 467)) :
subscript out of bounds
>
> cycle_patient_distribution_dasa_no2nd
[,1] [,2] [,3]
[1,] 1000 0 0
[2,] 700 200 100
[3,] 420 310 270

Your for loop goes to length(aaa) (5) and tries to access cycle_patient_distribution_dasa_no2nd[i,] when i==5. However, you'll see that cycle_patient_distribution_dasa_no2nd[5,] throws an error because the dimensions of that matrix are 3x3.
If your code does what you want otherwise, then you need to either change the ending index in your for loop to 3, or modify the dimensions of your matrix:
trans_matrix_dasa_no2nd <- matrix (,nrow=length(aaa),ncol=3)

Related

Creating more pseudo-random matrices same time in R? Comparing the points sign matching?

I can make one pseudo-random matrix with the following :
nc=14
nr=14
set.seed(111)
M=matrix(sample(
c(runif(58,min=-1,max=0),runif(71, min=0,max=0),
runif(nr*nc-129,min=0,max=+1))), nrow=nr, nc=nc)
The more important question: I need 1000 matrices with the same amount of negative, positive and zero values, just the location in the matrices need to be various.
I can make matrices one by one, but I want to do this task faster.
The less important question: If I have the 1000 matrices, I need to identify for every point of the matrices, that how many positive negative or zero value got there, for example:
MATRIX_A
[,1]
[9,] -0,2
MATRIX_B
[,1]
[9,] -0,5
MATRIX_C
[,1]
[9,] 0,1
MATRIX_D
[,1]
[9,] 0,0
MATRIX_E
[,1]
[9,] 0,9
What I need:
FINAL_MATRIX_positive
[,1]
[9,] (2/5*100)=40% or 0,4 or 2
,because from 5 matrix in this point were 2 positive value, and also need this for negative and zero values too.
If it isn't possible to do this in R, I can compare them "manually" in Excel.
Thank you for your help!
Actually you are almost there!
You can try the code below, where replicate can make 1000 times for generating the random matrix, and Reduce gets the statistics of each position:
nc <- 14
nr <- 14
N <- 1000
lst <- replicate(
N,
matrix(sample(
c(
runif(58, min = -1, max = 0),
runif(71, min = 0, max = 0),
runif(nr * nc - 129, min = 0, max = +1)
)
), nrow = nr, nc = nc),
simplify = FALSE
)
pos <- Reduce(`+`,lapply(lst,function(M) M > 0))/N
neg <- Reduce(`+`,lapply(lst,function(M) M < 0))/N
zero <- Reduce(`+`,lapply(lst,function(M) M == 0))/N
I use a function for your simulation scheme:
my_sim <- function(n_neg = 58, n_0 = 71, n_pos = 67){
res <- c(runif(n_neg, min=-1, max=0),
rep(0, n_0),
runif(n_pos, min=0, max=+1))
return(sample(res))
}
Then, I simulate your matrices (I store them in a list):
N <- 1000
nr <- 14
nc <- nr
set.seed(111)
my_matrices <- list()
for(i in 1:N){
my_matrices[[i]] <- matrix(my_sim(), nrow = nr, ncol = nc)
}
Finally, I compute the proportion of positive numbers for the position row 1 and column 9:
sum(sapply(my_matrices, function(x) x[1,9]) > 0)/N
# [1] 0.366
However, if you are interested in all the positions, these lines will do the job:
aux <- lapply(my_matrices, function(x) x > 0)
FINAL_MATRIX_positive <- 0
for(i in 1:N){
FINAL_MATRIX_positive <- FINAL_MATRIX_positive + aux[[i]]
}
FINAL_MATRIX_positive <- FINAL_MATRIX_positive/N
# row 1, column 9
FINAL_MATRIX_positive[1, 9]
# [1] 0.366

R language iteratively input a matrix

I'm trying to figure out how to iteratively load a matrix (this form part of a bigger function I can't reproduce here).
Let's suppose that I create a matrix:
m <- matrix(c(1:9), nrow = 3, ncol = 3)
m
This matrix can be named "m", "x" or whatsoever. Then, I need to load iteratively the matrix in the function:
if (interactive() ) { mat <-
readline("Your matrix, please: ")
}
So far, the function "knows" the name of the matrix, since mat returns [1] "m", and is a object listed in ls(). But when I try to get the matrix values, for example through x <- get(mat) I keep getting an error
Error in get(mat) : unused argument (mat)
Can anybody be so kind as to tell me what I'm doing wrong here?
1) Assuming you mean interactive, not iterative,
get_matrix <- function() {
nr <- as.numeric(readline("how many rows? "))
cat("Enter space separated data row by row. Enter empty row when finished.\n")
nums <- scan(stdin())
matrix(nums, nr, byrow = TRUE)
}
m <- get_matrix()
Here is a test:
> m <- get_matrix()
how many rows? 3
Enter space separated data row by row. Enter empty row when finished.
1: 1 2
3: 3 4
5: 5 6
7:
Read 6 items
> m
[,1] [,2]
[1,] 1 2
[2,] 3 4
[3,] 5 6
>
2) Another possibility is to require that the user create a matrix using R and then just give the name of the matrix:
get_matrix2 <- function(envir = parent.frame()) {
m <- readline("Enter name of matrix: ")
get(m, envir)
}
Test it:
> m <- matrix(1:6, 3)
> mat <- get_matrix2()
Enter name of matrix: m
> mat
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6

Source code for calculation of stationary distribution in R

Take a look at this link.
I am trying to understand the following source code meant for finding stationary distribution of a matrix:
# Stationary distribution of discrete-time Markov chain
# (uses eigenvectors)
stationary <- function(mat)
{
x = eigen(t(mat))$vectors[,1]
as.double(x/sum(x))
}
I tested the following source code myself:
> rm(list=ls())
>
> P <- matrix(c(0.66, 0.34,
+ 0.66, 0.34), nrow=2, ncol=2, byrow = TRUE)
>
> x <- eigen(t(P))
> x$values
[1] 1 0
$vectors
[,1] [,2]
[1,] 0.8889746 -0.7071068
[2,] 0.4579566 0.7071068
> y <- x$vectors[,1]
> y
[1] 0.8889746 0.4579566
>
looks like the command
y <- x$vectors[,1]
is selecting the 1st column of the matrix.
Why wasn't that simply written like the following?
# Stationary distribution of discrete-time Markov chain
# (uses eigenvectors)
stationary <- function(mat)
{
x = eigen(t(mat))
y = x[,1]
as.double(y/sum(y))
}
What was the reason for introduction of a dollar sign and vector keyword?
Let's test out your proposal:
> P <- matrix(c(0.66, 0.34, 0.66, 0.34), nrow=2, ncol=2, byrow = TRUE)
> x <- eigen(t(P))
> print(x)
eigen() decomposition
$values
[1] 1 0
$vectors
[,1] [,2]
[1,] 0.8889746 -0.7071068
[2,] 0.4579566 0.7071068
> y = x[,1]
This would produce the following error message:
Error in x[, 1] : incorrect number of dimensions
eigen returns a named list, with eigenvalues named values and eigenvectors named vectors. To access this component of the list. we use the dollar sign. Hence, that is why the code x$vectors which extract the matrix.

storing elements in an array format

i am trying to generate subsequent entries for Sn with this relation Sn=Sn-1 +Xn
my Xn is (1x2) matrix
Sn is (1x2) matrix
yn is a scalar
y=numeric()
s=matrix(0,nrow=1,ncol=2)
mu=(1,0)
cov= matrix(c(1,0,0,1),2,2)
invcov=solve(cov)
s[1,]=c(0,0)
for (i in 2:10){
x=mvrnorm(1,mu,cov)
s[i,]=s[i-1,]+x
y[i]=t(s[i,])%*%invcov%*%s[i,]
}
i tried the code above and i keep getting this error message "Error in [<-(*tmp*, i, , value = c(0.719138301056081, -1.96625516396033 : subscript out of bounds"
can i get any ideas on how to correct the error?
You can't append to a matrix like that:
m <- matrix(0, nrow=1, ncol=2)
m[2,] <- c(1, 1)
#Error in `[<-`(`*tmp*`, 2, , value = c(1, 1)) : subscript out of bounds
You could use rbind, but it's better to pre-allocate (you know the final size of the matrix):
m <- matrix(0, nrow=2, ncol=2)
m[2,] <- c(1, 1)
# [,1] [,2]
#[1,] 0 0
#[2,] 1 1
That way you also avoid the Second Circle of the R-Inferno.

Error assigning to a submatrix diagonal with drop=FALSE

When calling diag<-, you can pass a slice of the matrix and get the proper behavior, as long as you don't specify drop=FALSE.
> X <- matrix(0, 3, 3)
> diag(X[-1,]) <- c(1,2)
> X
[,1] [,2] [,3]
[1,] 0 0 0
[2,] 1 0 0
[3,] 0 2 0
Specifying drop=false is a different story
> diag(X[-1,,drop=FALSE]) <- c(3,4)
Error in diag(X[-1, , drop = FALSE]) <- c(3, 4) :
incorrect number of subscripts
Note:
> identical(X[-1,], X[-1,,drop=FALSE])
[1] TRUE
As noted by MrFlick, assignment to a slice when the drop argument results in the same error:
X[1,] <- 1
X[1,,drop=TRUE] <- 2
Error in X[1, , drop = TRUE] <- 2 : incorrect number of subscripts
Why is this happening?
According to the ?"[<-" help page, drop= "only works for extracting elements, not for the replacement" Thus you are not allowed to use a <- with drop which is basically what diag() is doing. As in my comment above, something like X[,,drop=TRUE] <- 1:9 is not allowed either. Too bad the error message isn't a bit more specific.

Resources