lightsnail lightsnail - 17 days ago 4
R Question

Change the character in a matrix according to specific rules

a
is a matrix,

a<- matrix(c("A","B","0","1","A","C","D","B","A","C","0","D","B","1","C","D"),4)

> a
[,1] [,2] [,3] [,4]
[1,] "A" "A" "A" "B"
[2,] "B" "C" "C" "1"
[3,] "0" "D" "0" "C"
[4,] "1" "B" "D" "D"


We find that there are four types of characters in the matrix
a
, those are, "A", "B", "C" and "D".
Now we assume that there is a 40% possibility for each character to change into one of the rest of the three characters. For example, "A" has a 40% possibility to change into "B","C" or "D"; "B" has a 40% possibility to change into "A","C" or "D";......

I used the following code with a seed set, the answer is right.

set.seed(2016)
pob <- 0.4
a[a=="A"] <- ifelse(runif(sum(a=="A")) <= pob, sample(c(1:4)[-1],sum(a=="A"),replace = T), 1)
a[a=="B"] <- ifelse(runif(sum(a=="B")) <= pob, sample(c(1:4)[-2],sum(a=="B"),replace = T), 2)
a[a=="C"] <- ifelse(runif(sum(a=="C")) <= pob, sample(c(1:4)[-3],sum(a=="C"),replace = T), 3)
a[a=="D"] <- ifelse(runif(sum(a=="D")) <= pob, sample(c(1:4)[-4],sum(a=="D"),replace = T), 4)

a[a==1] <- "A"
a[a==2] <- "B"
a[a==3] <- "C"
a[a==4] <- "D"

> a
[,1] [,2] [,3] [,4]
[1,] "B" "A" "B" "C"
[2,] "D" "C" "A" "A"
[3,] "0" "B" "0" "C"
[4,] "C" "A" "D" "D"


But I wonder whether there is a much easier way to work this problem out, thanks in advance.

Modified


As there is "0" and "1" which are not characters in the matrix
a
, I need to change my original code as follows:

set.seed(2016)
pob <- 0.4
a[a=="A"] <- ifelse(runif(sum(a=="A")) <= pob, sample(c(1:4)[-1],sum(a=="A"),replace = T), "one")
a[a=="B"] <- ifelse(runif(sum(a=="B")) <= pob, sample(c(1:4)[-2],sum(a=="B"),replace = T), "two")
a[a=="C"] <- ifelse(runif(sum(a=="C")) <= pob, sample(c(1:4)[-3],sum(a=="C"),replace = T), "three")
a[a=="D"] <- ifelse(runif(sum(a=="D")) <= pob, sample(c(1:4)[-4],sum(a=="D"),replace = T), "four")

a[a=="one"] <- "A"
a[a=="two"] <- "B"
a[a=="three"] <- "C"
a[a=="four"] <- "D"

> a
[,1] [,2] [,3] [,4]
[1,] "2" "3" "A" "1"
[2,] "B" "2" "C" "1"
[3,] "0" "D" "0" "1"
[4,] "1" "B" "2" "2"

Answer

if I understand correctly, the following code does what you want, except the singular 0 and 1s.

a <- matrix(c("A","B","0","1","A","C","D","B","A","C","0","D","B","1","C","D"),4)

# states that are subjected to mutation
s <- c('A', 'B', 'C', 'D')
# matrix of transition prob
b <- matrix(1, nrow = 4, ncol = 4, dimnames = list(s, NULL))
diag(b) <- 0

# mutation prob
prob <- 0.4

# sites that can be changed
indx <- a %in% s
a[indx] <- ifelse(
    runif(sum(indx)) > prob,
    a[indx],
    sapply(a[indx], function(i) sample(s, 1, prob = b[i, ]))
)