I have a matrix that contains integer values that represent the index of the item in an array and I'd like to switch out item 1 for the values[1] and so on for each item in the values array.
Some code to demonstrate what I'd like
> m = matrix(1:3, ncol=3, nrow=3)
> m
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 2 2 2
[3,] 3 3 3
> replace(m, 1="a", 2="b", 3="c")
> m
[,1] [,2] [,3]
[1,] "a" "a" "a"
[2,] "b" "b" "b"
[3,] "c" "c" "c"
Basically it takes 1 and turns it into "a" and so on. It seems like if I try to do this with a for loop it changes after the first iteration from int to string and since I'd like to do this with any object type that's not great behavior.
I can think of three possibilities to solve this
m <- matrix(1:3, 3, 3) # Your data
1
Either define a function that will get a vector in the correct matching order (the first entry will match the first unique value in m, etc.)
vec <- c("Ralf", "Jhons", "Pete")
Then you can define a simple function such as
Match_func <- function(x, y) "dim<-"(y[match(unique(x), seq_along(y))], dim(x))
Test
Match_func(m, vec)
# [,1] [,2] [,3]
# [1,] "Ralf" "Ralf" "Ralf"
# [2,] "Jhons" "Jhons" "Jhons"
# [3,] "Pete" "Pete" "Pete"
2
The second option will be to define your manual replace function, something like
Match_func2 <- function(x, ...) {
temp <- list(...)[[1]]
"dim<-"(temp[match(x, as.numeric(names(temp)))], dim(x))
}
Test
Match_func2(m, c("1" = "a", "2" = "b", "3" = "c"))
# [,1] [,2] [,3]
# [1,] "a" "a" "a"
# [2,] "b" "b" "b"
# [3,] "c" "c" "c"
3
You can also make a use of plyr::revalue
library(plyr)
Match_func3 <- function(x, ...) {
temp <- list(...)[[1]]
"dim<-"(revalue(as.character(x), temp), dim(x))
}
Test
Match_func3(m, c("1" = "a", "2" = "b", "3" = "c"))
# [,1] [,2] [,3]
# [1,] "a" "a" "a"
# [2,] "b" "b" "b"
# [3,] "c" "c" "c"
Note: The last approach is the safest in case you don't want to replace all the unique values
Here's an option, starting with a character matrix so that you don't need to worry about making a copy or coercion of the original matrix.
m = matrix(as.character(1:3), ncol=3, nrow=3)
old <- as.character(1:3)
new <- c("a", "b", "c")
for (i in 1:length(old)) {
m <- ifelse(m == old[i], new[i], m)
}
Related
I would like to generate an array of data matrices, where each matrix will refer to a different scenario, for the purpose of example I have included only 1
p13=0.493;p43=0.325;p25=0.335;p35=0.574;p12=0.868
std_e2=sqrt(1-p12^2);std_e2
std_e3=sqrt(1-(p13^2+p43^2));std_e3
std_e5=sqrt(1-(p25^2+p35^2+2*p25*p35*(p13*p12)));std_e5
scenario_1<-matrix(c(3,0,0,0,0),ncol = 5,nrow = 1);scenario_1
genereting_fuction<- function(n,scenario){
sample <- vector("list")
for (i in scenario){
x1=rnorm(n)+scenario[i,1]
x4=rnorm(n)+scenario[i,4]
x2=x1*p12+std_e2*rnorm(n)+scenario[i,2]
x3=x1*p13+x4*p43+std_e3*rnorm(n)+scenario[i,3]
x5=x2*p25+x3*p35+std_e5*rnorm(n)+scenario[i,5]
sample[[i]]=cbind(x1,x2,x3,x4,x5)
colnames(sample[[i]])<-c("x1","x2","x3","x4","x5")
}
sample
}
array_scenari<-array(dim=c(5,5,2));array_scenari
for(j in 1:nrow(scenario_1)){
set.seed(1234)
dati_prova<- sapply(rep(1,5), function(x) genereting_fuction(x,scenario_1),simplify = 'array');dati_prova
dati_prova<-do.call(rbind.data.frame, dati_prova);dati_prova<-as.matrix(dati_prova);dati_prova
dati_prova<-as.matrix(dati_prova)
array_scenari[,,j]<-dati_prova[]
}
I can't understand why it doesn't work and gives me an error
It's hard to give a concrete answer without a working reproducible example, since your function contains externally defined variables. However, the source of the error is clear. When you create an empty array with array() it has a single fixed dimension:
matrix_classification <- array()
dim(matrix_classification)
#> [1] 1
And if you try to write into its third dimension you get an error:
k <- 1
matrix_classification[, , k] <- "x"
#> Error in matrix_classification[, , k] <- "x": incorrect number of subscripts
If you want to write into an array you should define its dimensions first. For example, the following creates an empty 5 x 5 x 5 array:
matrix_classification <- array("", dim = c(5, 5, 5))
dim(matrix_classification)
#> [1] 5 5 5
And if we want to write a matrix into the kth slice we can do:
matrix_classification[, , k] <- matrix(sample(letters, 25), nrow = 5)
matrix_classification[,,1]
#> [,1] [,2] [,3] [,4] [,5]
#> [1,] "a" "d" "k" "t" "c"
#> [2,] "f" "b" "n" "m" "s"
#> [3,] "u" "q" "y" "o" "j"
#> [4,] "l" "g" "h" "w" "v"
#> [5,] "r" "i" "e" "p" "z"
Created on 2022-03-06 by the reprex package (v2.0.1)
I'm trying to populate a multi-dimensional array with two vectors of the same length. The input data should alternate between the vectors, so that the first input is the first object of the first vector, the second input is the first object of the second vector and so on.
I searched for similar problems on this site and found the function rbind(), however, this will not work as soon as my third dimension is unequal to 1.
In short, I want to achieve this:
a <- 1:6
b <- c("a","b","c","d","e","f")
# output array
, , 1
[,1] [,2]
[1,] "1" "a"
[2,] "2" "b"
[3,] "3" "c"
, , 2
[,1] [,2]
[1,] "4" "d"
[2,] "5" "e"
[3,] "6" "f"
I have a working solution below using three for-loops, but this seems overly complicated.
a <- 1:6
b <- c("a","b","c","d","e","f")
len <- prod(length(a)+length(b))
myarray <- array(rep(F,len),dim=c(3,2,2))
counter <- 1
for (n in 1:dim(myarray)[3]) { # n 2
for (r in 1:dim(myarray)[1]) { # rows 3
for (c in 1:dim(myarray)[2]) { # columns 2
if (c %% 2 != 0) {
myarray[r,c,n] <- a[counter]
} else {
myarray[r,c,n] <- b[counter]
}
}
counter <- counter + 1
}
}
Is there an easier approach?
(I'm sure I'm missing something very simple here, but I'm new to R and can't figure it out myself)
Thank you for reading!
[EDIT]
The code should be applyable to a data set with any vector length and any dimension dim = c(x,y,z).
Example data can be found on Dryad Database https://doi.org/10.5061/dryad.mp713, "Table 1 Arctic char landmarks", which contains 13 pairs of x-y-coordinates from 121 individuals of arctic char fish (dim=c(13,2,121)).
Here is my solution for the problem with dim = c(13,2,121):
M <- cbind(a, b)
array(sapply(seq(1, length(a), 13), function(i) M[i:(i+12),]), c(13,2,121))
Do not forget to store the result Mneu <- ...
For your small example:
M <- cbind(a, b);
array(sapply(seq(1, length(a), 3), function(i) M[i:(i+2),]), c(3,2,2))
Form an array and then permute the dimensions:
aperm(array(cbind(a, b), c(3, 2, 2)), c(1, 3:2))
giving:
, , 1
[,1] [,2]
[1,] "1" "a"
[2,] "2" "b"
[3,] "3" "c"
, , 2
[,1] [,2]
[1,] "4" "d"
[2,] "5" "e"
[3,] "6" "f"
Note
We can generalize the example slightly:
n <- 6 # must be 26 or less so that we can use letters below
a <- 1:n
b <- head(letters, n)
aperm(array(cbind(a, b), c(n/2,2,2)), c(1, 3:2))
I am having 3 matrices that store values from triplicate measurements and would like to take the mean of the 3 matrices.
So let's say the three matrices are:
m1<-t(matrix(c("text", 1:3), ncol=2, nrow=4))
m2<-t(matrix(c("text", 1:3), ncol=2, nrow=4))
m3<-t(matrix(c("text", 1:3), ncol=2, nrow=4))
> m1
[,1] [,2] [,3] [,4]
[1,] "text" "1" "2" "3"
[2,] "text" "1" "2" "3"
> m2
[,1] [,2] [,3] [,4]
[1,] "text" "1" "2" "3"
[2,] "text" "1" "2" "3"
> m3
[,1] [,2] [,3] [,4]
[1,] "text" "1" "2" "3"
[2,] "text" "1" "2" "3"
I would like to have this for every position of the matrices:
mean(m1[i,j], m2[i,j], m2[i,j])
So I tried it with 2 for loops:
for(i in ncol(m1)){
for(j in nrow(m1)){
means[i,j]<-mean(m1[i,j], m2[i,j], m2[i,j])
}
which obviously doesn't work
The text in the first column isn't an issue if NA is returned.
Anyone could help me please?
Thanks!
We can place it in a list, convert to numeric and use Reduce
lst <- lapply(list(m1[, -1], m2[,-1], m3[, -1]), as.numeric)
Reduce(`+`,lst)/length(lst)
If there are many matrices starting with 'm', we can use mget
lst <- lapply(mget(paste0("m", 1:3)), function(x) as.numeric(x[,-1]))
and then do the Reduce step.
I'm afraid I can't find the answer to this so I need your expertise.
I need to randomize a set of data in R, where the datasets are sets of choices (represented by letters here) in pairs; however, I also need to, for each set, randomize the order of precedence (which goes first). Additionally, I need to include a negative control (XX). It would look something like this:
(1) X A or A X
(2) X B or B X
(3) X C or C X
(4) X D or D X
(5) X E or E X
(6) XX
I can randomize 1-6 easy enough using sample(1:6, 4), but I don't know how to add in randomization for the pair order as well. Any ideas are great!
Assuming your original set of data looks like this:
li
[[1]]
[1] "X" "A"
[[2]]
[1] "X" "B"
[[3]]
[1] "X" "C"
[[4]]
[1] "X" "D"
[[5]]
[1] "X" "E"
[[6]]
[1] "X" "X"
You can randomize it both at the level of list and at the level of each pair as this:
lapply(li, function(pair) pair[sample(1:2)])[sample(1:6)]
[[1]]
[1] "X" "D"
[[2]]
[1] "B" "X"
[[3]]
[1] "E" "X"
[[4]]
[1] "X" "X"
[[5]]
[1] "X" "A"
[[6]]
[1] "C" "X"
If i understand the question, the below is a little brute force, but I believe answers your question
s<- c("a","b","c","d","e","x")
n<-6
(x<-cbind(sample(s,n),rep("x",n)))
for (i in 1:n) {
if(sample(1:2,1)==2) {
tmp<-x[i,1]
x[i,1] <- x[i,2]
x[i,2] <- tmp
}
}
x
If I understand; you have LETTERS[1:5] and LETTERS[24] (X) that you are sampling from twice, with random ordering. This should do it;
c(sample(LETTERS[c(1:5, 24)], 1), LETTERS[24])[sample(2)]
Broken down;
c( ## combination of
sample(LETTERS[c(1:5, 24)], 1), ## A:E, X, sampled once
LETTERS[24]) ## and X
[sample(2)] ## re-sampled
e.g.
set.seed(1337)
[1] "X" "D"
A list of some possible outcomes;
set.seed(1337)
replicate(10, c(sample(LETTERS[c(1:5, 24)], 1), LETTERS[24])[sample(2)])
[,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,] "X" "C" "X" "X" "E" "X" "C" "E" "X" "X"
[2,] "D" "X" "X" "A" "X" "A" "X" "X" "D" "X"
How can I generate all of the 6 combinations of 2 treatments (A,B) in blocks of 4, such that in each block there is an equal number of A's and B's, using R?
"AABB","ABAB","ABBA","BBAA","BABA","BAAB"
P.S. The number of combinations is calculated as follows:
If
T = #treatments
n = #treatments in each block = k*T,
The number of combinations equals n! / [k!*k! (T times)]
Thank you
Something like this should work:
library(gtools)
t <- c('A','B')
k <- 2
n <- k * length(t)
t2 <- rep(t, k)
m <- permutations(n,n)
res <- unique(apply(m,MARGIN=1,function(x) paste(t2[x],collapse='')))
--------------------------------------------------------------------
res
[1] "ABAB" "ABBA" "AABB" "BAAB" "BABA" "BBAA"
The multicool package implements an algorithm for permuting multisets --- exactly the task you want to have performed. Here's an example of what it can do:
library(multicool)
# Create a simple convenience function
enumAllPartitions <- function(multiset) {
m1 <- initMC(multiset) # Initialize the permutation object
N <- fact(length(multiset))/ # Calculate number of permutations
prod(fact(table(multiset)))
sapply(seq_len(N), function(X) paste(nextPerm(m1), collapse=""))
}
# Try it out with a few different multisets
x <- c("A", "A", "B", "B")
y <- c("G", "L", "L", "L")
z <- c("X", "X", "Y", "Z", "Z")
lapply(list(x,y,z), enumAllPartitions)
[[1]]
[1] "BBAA" "ABBA" "BABA" "ABAB" "AABB" "BAAB"
[[2]]
[1] "LLLG" "GLLL" "LGLL" "LLGL"
[[3]]
[1] "ZZYXX" "XZZYX" "ZXZYX" "ZZXYX" "XZZXY" "ZXZXY" "XZXZY" "XXZZY" "ZXXZY"
[10] "ZZXXY" "YZZXX" "ZYZXX" "XZYZX" "ZXYZX" "YZXZX" "XYZZX" "YXZZX" "ZYXZX"
[19] "XZYXZ" "ZXYXZ" "XZXYZ" "XXZYZ" "ZXXYZ" "YZXXZ" "XYZXZ" "YXZXZ" "XYXZZ"
[28] "XXYZZ" "YXXZZ" "ZYXXZ"
The expected solution can also be achieved using the new iterpc package.
I <- iterpc(c(2, 2), labels=c("A", "B"), ordered=TRUE)
getall(I)
# [,1] [,2] [,3] [,4]
# [1,] "A" "A" "B" "B"
# [2,] "A" "B" "A" "B"
# [3,] "A" "B" "B" "A"
# [4,] "B" "A" "A" "B"
# [5,] "B" "A" "B" "A"
# [6,] "B" "B" "A" "A"