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.
Related
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 have two matrices in a list:
colList <- list()
colList[["V1"]] <- as.matrix(c("asd", "asd", "asd"))
colList[["V2"]] <- as.matrix(c("das", "das", "das"))
And I want to cbind the values of a data.frame value.frame$keyID to each sublist. The first value (2000) to the first sublist, the second value (3000) to the second sublist.
Here the value.frame:
value.frame <- data.frame(keyID =c("2000", "3000"))
The result should look like this:
colList <- list()
colList[["V1"]] <- matrix(c("asd", "asd", "asd", 2000, 2000, 2000),
nrow=3,
ncol=2)
colList[["V2"]] <- matrix(c("das", "das", "das", 3000, 3000, 3000),
nrow=3,
ncol=2)
I tried it with the following code, but the result is not the desired one. Hope someone can help me.
mapply( cbind, colList, paste(value.frame[,1]))
Using lapply and seq_along
nms <- names(colList)
colList <- lapply(seq_along(colList), x=colList,
y=as.character(value.frame$keyID), function(j, x, y) {
cbind(x[[j]], y[j])
})
names(colList) <- nms
colList[["V1"]]
[,1] [,2]
[1,] "asd" "2000"
[2,] "asd" "2000"
[3,] "asd" "2000"
colList[["V2"]]
[,1] [,2]
[1,] "das" "3000"
[2,] "das" "3000"
[3,] "das" "3000"
You could do this with mapply using the option SIMPLIFY=FALSE
mapply(cbind, colList, as.character(value.frame$keyID), SIMPLIFY=FALSE)
#$V1
# [,1] [,2]
#[1,] "asd" "2000"
#[2,] "asd" "2000"
#[3,] "asd" "2000"
#$V2
# [,1] [,2]
#[1,] "das" "3000"
#[2,] "das" "3000"
#[3,] "das" "3000"
Or using Map which is a wrapper for mapply(..., SIMPLIFY=FALSE)
Map(cbind, colList, as.character(value.frame$keyID))
I am having some issues working a forloop which allows me to take the following matrix:
> cd
[,1] [,2]
[1,] -142.5066 -132.9431
[2,] -161.6038 -166.9276
and renaming the elements along the columns. Specifically, I want do the following:
if cd[1,1] > cd[1,2] , then I want cd[1,2] == 'STOP'
else cd[1,2]==cd[1,2]
my code right now for a forloop for K rows is:
for(k in 1:2){
if(cd[1,k]>cd[2,k]){
cd[2,k]<-'STOP'
}else{
cd[2,k]<-cd[2,k]
}
print(cd)
}
The output is the following:
[,1] [,2]
[1,] "-142.50660967154" "-132.943085827163"
[2,] "STOP" "-166.92760911847"
[,1] [,2]
[1,] "-142.50660967154" "-132.943085827163"
[2,] "STOP" "-166.92760911847"
Essentially, after running the loop, I want the result to be:
> cd
[,1] [,2]
[1,] -142.5066 -132.9431
[2,] STOP STOP
Thank you again.
When you have a matrix in r, all the elements have to be the same type. At first, you have all numeric elements, so the first comparison works, but when it makes it "stop", then it makes them all character, and "-3" is less than "-4", characterwise. Your options are to use a dataframe instead of a matrix, or use as.numeric(cd[1,k])...
> cd <- matrix(c(-1,-2,-3,-4), nrow = 2)
> for(k in 1:2){
+ if(as.numeric(cd[1,k])>as.numeric(cd[2,k])){
+ cd[2,k]<-'STOP'
+ } else{cd[2,k]<-cd[2,k]}
+ print(cd)
+ }
[,1] [,2]
[1,] "-1" "-3"
[2,] "STOP" "-4"
[,1] [,2]
[1,] "-1" "-3"
[2,] "STOP" "STOP"
With a matrix there can be no conflicting data types in a column so the numeric values are coerced to character. If you want separate types, use a data.frame:
cd <- matrix(c(-142.5066, -132.9431, -161.6038, -166.9276), nrow = 2, byrow = TRUE)
cd[2, ] <- ifelse(cd[1,] > cd[2, ], "STOP", cd[2,])
cd
[,1] [,2]
[1,] "-142.5066" "-132.9431"
[2,] "STOP" "STOP"
Instead of using a loop, you could try the following:
cd[cd[,1] > cd[,2]] <- 'STOP'
[,1] [,2]
cd "-142.5066" "-132.9431"
"STOP" "STOP"
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)
}
I have a matrix "a" like the following:
a<-rbind(c("a1","ost1;ost2;ost3","utr;body;pro"),
c("a2","idh1;idh2","pro;body"),
c("a3","dnm1","body"))
>a
[,1] [,2] [,3]
[1,] "a1" "ost1;ost2;ost3" "utr;body;pro"
[2,] "a2" "idh1;idh2" "pro;body"
[3,] "a3" "dnm1" "body"
I want to get a matrix "b" like this
[,1] [,2] [,3]
[1,] "a1" "ost1" "utr"
[2,] "a1" "ost2" "body"
[3,] "a1" "ost3" "pro"
[4,] "a2" "idh1" "pro"
[5,] "a2" "idh2" "body"
[6,] "a3" "dnm1" "body"
OK, get it:
b<-do.call(rbind, (apply(a, 1, function(x) {do.call(cbind, strsplit(x,";"))})))
Your solution, without the unnecessary parentheses:
do.call(rbind, apply(a, 1, function(x) do.call(cbind, strsplit(x, ";"))))
This also works:
do.call(rbind, lapply(apply(a, 1, strsplit, ';'), do.call, what = cbind))
Not that there is anything wrong with using anonymous functions (function(x){...}), but some people find it more "elegant" without any.