Bharat Desai
Bharat Desai

Reputation: 123

how to iterate through each element in a matrix in r

Context: I am iterating through several variables in my dataset, and performing a pairwise t.test between the factors for each of those variables. ( which i have succesfully managed to perform). and example of the result i have is as so:

Table of P-values between classes 11,12,13 and 14

My next task with which i am having difficulty with is presenting each of those values as a table where for each element, if its value is below a certain threshold (say .05) then the table should dynamically display if the test between the two classes passes ( represented by a 1 if below 0.05 and a 0 if above 0.05) the table should also display a ratio of the number of tests passed as a proportion of the number of tests conducted. ( number of entries in the table below 0.05 over the total number of entries in the diagonal matrix). In reference to the image above the output should look like this: Ideal Matrix

And so the problem, is essentially that i have to iterate through the first matrix (exclude the first row and first column), apply a function then generate a new row and header with a row and column summary! Any help or advice would be appreciated.

Upvotes: 1

Views: 2569

Answers (2)

Rui Barradas
Rui Barradas

Reputation: 76402

Here is one way of doing what you want.

First I will make up a matrix.

set.seed(3781)
pval <- matrix(runif(9, 0, 0.07), 3)
is.na(pval) <- upper.tri(pval)
dimnames(pval) <- list(12:14, 11:13)

Now the question.

Ideal <- matrix(as.integer(pval < 0.05), nrow(pval))
dimnames(Ideal) <- dimnames(pval)
Ideal
#   11 12 13
#12  1 NA NA
#13  1  1 NA
#14  1  0  0


r <- sum(Ideal, na.rm = TRUE)/sum(!is.na(Ideal))
r
#[1] 0.6666667

So now all what is needed is to add the extra row and column.

Ideal <- rbind(Ideal, colSums(!is.na(Ideal)))
Ideal <- cbind(Ideal, rowSums(Ideal, na.rm = TRUE))
Ideal[nrow(pval) + 1, ncol(pval) + 1] <- r
rownames(Ideal)[nrow(pval) + 1] <- "SumCount"
colnames(Ideal)[nrow(pval) + 1] <- "SumScore"

Upvotes: 1

LAP
LAP

Reputation: 6685

R is not really a useful tool to build such a table, but here is one solution.

Data (shortened the decimals for convenience):

mat <- matrix(c(.569, .0001, .1211, NA, .0001, .3262, NA, NA, .0001), nrow = 3)

       [,1]   [,2]  [,3]
[1,] 0.5690     NA    NA
[2,] 0.0001 0.0001    NA
[3,] 0.1211 0.3262 1e-04

First we convert to the 0,1 scheme by using ifelse with the condition < .05:

mat <- ifelse(mat < .05, 1, 0)

Then we add another column with the rowSums:

mat <- cbind(mat, rowSums(mat, na.rm = T))

Then we add another row with the colSums of the boolean matrix !is.na(mat), therefore counting the numbers of non NA per column:

mat <- rbind(mat, colSums(!is.na(mat)))

Then we change the lower right cell to the sum of the inner matrix divided by the amount of non NA of the inner matrix:

mat[nrow(mat), ncol(mat)] <- sum(mat[1:nrow(mat)-1, 1:ncol(mat)-1], na.rm = T)/
                             sum(!is.na(mat[1:nrow(mat)-1, 1:ncol(mat)-1]))

Finally, we change the row and column names:

rownames(mat) <- c(12:14, "SumCount")
colnames(mat) <- c(11:13, "SumScore")

End result:

> mat
         11 12 13 SumScore
12        0 NA NA      0.0
13        1  1 NA      2.0
14        0  0  1      1.0
SumCount  3  2  1      0.5

Notice that no looping was necessary, as R is very efficient with vectorized operations on matrices.

Upvotes: 3

Related Questions