Compute matrix based on logical expression [duplicate] - r

I have two matrices:
mat <- matrix(1:6, 2, 3)
mat2 <- matrix(1:2, 2, 3)
and a parameter
a <- 1
using ifelse, is it possible to return a matrix when a is a certain value?
the code that I am using, does not work. For example:
mat.new <- ifelse(a == 1, mat, mat2)

The length of the return is completely decided by length(a == 1). See also the helpfile with ?ifelse. Your code will only return a single value.
ifelse targets vector input / output. Even if you get the length correct, say: ifelse(rep(TRUE, 6), mat, mat2), you get a vector rather than a matrix output. So an outer matrix call to reset dimension is necessary.
Tip 1:
For your example, looks like a simple result <- if (a == 1) mat else mat2 is sufficient. No need to touch ifelse.
Tip 2:
It is not impossible to ask ifelse to return a matrix, but you have to protect it by a list (remember a list is a vector):
ifelse(TRUE, list(mat), list(mat2))
But, this is inconvenient.

Related

How do I replace a value in a matrix/dataframe if that value is less than the corresponding value in a list?

I have a (20x12)matrix with numerical values and a list of 12 numbers. If a value in the matrix is less than the value in the list in the corresponding column index, I would like to replace it. How can I do it?
mat <- matrix(rpois(240,10),ncol=12)
list_to_replace <- rpois(12,10)
I think this is what is desired. Use the same logical index to pick out the positions of the possible replacements and the re-assignments:
t( apply(mat, 1, function(r) {
r[ r < list_to_replace] <- list_to_replace[ r < list_to_replace]; r}) )
The t is needed to transpose back because the apply function always delivers column-oriented result, even when the input is rowwise.
BTW; you would be well advised to only use the term "list" when referring to an R object with class "list". What you have is a "vector".
You could use the code below:
index <- t(t(mat) < list_to_replace)
mat[index] <- list_to_replace[which(index, TRUE)[, 2]]

I want to apply two functions one function on the block diagonal and the second function on the off-diagonal elements in the data frame

df<- data.frame(a=c(1:10), b=c(21:30),c=c(1:10), d=c(14:23),e=c(11:20),f=c(-6:-15),g=c(11:20),h=c(-14:-23),i=c(4:13),j=c(1:10))
In this data frame, I have three block-diagonal matrices which are as shown in the image below
I want to apply two functions, one is the sine function for block diagonal and the second is cosine function for the other elements and generates the same structure of the data frame.
sin(df[1:2,1:2])
sin(df[3:5,3:5])
sin(df[6:10,6:10])
cos(the rest of the elements)
1) outer/arithmetic Create a logical block diagonal matrix indicating whether the current cell is on the block diagonal or not and then use that to take a convex combination of the sin and cos values giving a data.frame as follows:
v <- rep(1:3, c(2, 3, 5))
ind <- outer(v, v, `==`)
ind * sin(df) + (!ind) * cos(df)
2) ifelse Alternately, this gives a matrix result (or use as.matrix on the above). ind is from above.
m <- as.matrix(df)
ifelse(ind, sin(m), cos(m))
3) Matrix::bdiag Another approach is to use bdiag in the Matrix package (which comes with R -- no need to install it).
library(Matrix)
ones <- function(n) matrix(1, n, n)
ind <- bdiag(ones(2), ones(3), ones(5)) == 1
Now proceed as in the last line of (1) or as in (2).
If it's okay for you that the result is stored in a new data frame you could change the order of your instructions and do it like that:
ndf <- cos(df)
ndf[1:2,1:2] <- sin(df[1:2,1:2])
ndf[3:5,3:5] <- sin(df[3:5,3:5])
ndf[6:10,6:10] <- sin(df[6:10,6:10])

R apply and for loop calculation

Would someone be able to explain why this apply doesn't work correctly? I wanted to normalise all the values in each row by the sum of the values in each row - such that the sum of each row =1 However, when I did this using an apply function, the answer is incorrect.
data <- data.frame(Sample=c("A","B","C"),val1=c(1235,34567,234346),val2=c(3445,23446,234235),val3=c(457643,234567,754234))
norm <- function(x){
x/sum(x)}
applymeth <- data
applymeth[,2:4] <- apply(applymeth[,2:4], 1, norm)
rowSums(applymeth[,2:4])
loopmeth <- data
for(i in 1:nrow(data)){
loopmeth[i,2:4] <- norm(loopmeth[i,2:4])
}
rowSums(loopmeth[,2:4])
Thanks.
apply() gives you (in the result) a matrix column by column - in your case from a row-by-row input. You have to transpose the result:
applymeth <- data
applymeth[,2:4] <- t(apply(applymeth[,2:4], 1, norm))
rowSums(applymeth[,2:4])
Have a look at
apply(matrix(1:12, 3), 1, norm)
The reason for this result of apply() is a convention:
in a matrix or a multidimensional array the index of the first dimension is running first, then the second and so on. Example:
array(1:12, dim=c(2,2,3))
So (without any reorganisation of the data) apply() produces one column after the other. This behavior not depends on the parameter MARGIN= of the function apply().

Return a matrix with `ifelse`

I have two matrices:
mat <- matrix(1:6, 2, 3)
mat2 <- matrix(1:2, 2, 3)
and a parameter
a <- 1
using ifelse, is it possible to return a matrix when a is a certain value?
the code that I am using, does not work. For example:
mat.new <- ifelse(a == 1, mat, mat2)
The length of the return is completely decided by length(a == 1). See also the helpfile with ?ifelse. Your code will only return a single value.
ifelse targets vector input / output. Even if you get the length correct, say: ifelse(rep(TRUE, 6), mat, mat2), you get a vector rather than a matrix output. So an outer matrix call to reset dimension is necessary.
Tip 1:
For your example, looks like a simple result <- if (a == 1) mat else mat2 is sufficient. No need to touch ifelse.
Tip 2:
It is not impossible to ask ifelse to return a matrix, but you have to protect it by a list (remember a list is a vector):
ifelse(TRUE, list(mat), list(mat2))
But, this is inconvenient.

Force apply to return a list

I have a matrix and a function that takes a vector and returns a matrix. I want to apply the function to all rows of the matrix and rbind all results together. For example
mat <- matrix(1:6, ncol=2)
f <- function (x) cbind(1:sum(x), sum(x):1)
do.call(rbind, apply(mat, 1, f))
This works perfectly since the returned matrices have different numbers of rows so apply returns a list. But if they happen to have the same numbers of rows this does not work anymore:
mat <- f(3)
apply(mat, 1, f)
apply returns a matrix from which I cannot get the result I want. Is it possible to force apply to return a list or is there another solution?
This is why I love the plyr package. It has a number of --ply functions that all work in the same way. The first letter corresponds to what you have as input and the second method corresponds to what you have as output (l for lists, a for arrays, d for data frames).
So the alply() function works similar to apply() but always returns a list:
alply(mat, 1, f)
You have to split matrix mat before applying function f.
list_result <- lapply(split(mat,seq(NROW(mat))),f)
matrix_result <- do.call(rbind,list_result)

Resources