Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiplying elements of a matrix depending on numbers and strings of the row names and column names (2)

Tags:

r

This question is similar to the one I asked here. I again have a very large matrix with row and column names that are identical. These names are a three letter string followed by a number. The three letter string repeats itself and only the number changes. After several repetitions, the string changes and the number starts from 1 again.

Basically what I'm looking for is doing specific calculations based on each element's row name and column name.

I will give a small example of what I'm looking for. Here is a matrix a:

matrix <- matrix(c(1:36), nrow = 6, byrow = TRUE)

names <- paste(rep(c("aaa" , "bbb", "ccc"), each = 2) , rep(c(1:2) , times = 3))

rownames(matrix) <- names
colnames(matrix) <- names

that gives:

      aaa 1 aaa 2 bbb 1 bbb 2 ccc 1 ccc 2
aaa 1     1     2     3     4     5     6
aaa 2     7     8     9    10    11    12
bbb 1    13    14    15    16    17    18
bbb 2    19    20    21    22    23    24
ccc 1    25    26    27    28    29    30
ccc 2    31    32    33    34    35    36

For each element of this matrix I would like to do a multiplication. It's a bit hard to explain with words.

If an element of a matrix has a row name with a different three letter string than its column name, I would match the number appearing after the string and multiply "first 3 letter string number" with "second three letter string with same number".

If "aaa" is matched with "bbb" then:

matrix[aaa (number n), aaa (number m)] * matrix[bbb (number n), bbb (number m)]

if "aaa" is equal to "aaa" then

matrix[aaa (number n), aaa (number m)] * matrix[aaa (number n), aaa (number m)]

or basically the element squared.

So I will give some examples of what I am looking for:

  • in matrix["aaa 1", "aaa 2"] I would multiply matrix["aaa 1", "aaa 2"] with matrix["aaa 1", "aaa 2"] (2*2) giving 4

  • in matrix["aaa 1", "bbb 2"] I would multiply matrix["aaa 1", "aaa 2"] with matrix["bbb 1", "bbb 2"] (2*16) giving 32

  • in matrix["bbb 2", "ccc 1"] I would multiply matrix["bbb 2", "bbb 1"] with matrix["ccc 2", "ccc 1"] (21*35) giving 735

In the end, the matrix (called d) should give:

      aaa 1 aaa 2 bbb 1 bbb 2 ccc 1 ccc 2
aaa 1     1     4    15    32    29    60
aaa 2    49    64   147   176   245   288
bbb 1    15    32   225   256   435   480
bbb 2   147   176   441   484   735   792
ccc 1    29    60   435   480   841   900
ccc 2   245   288   735   792  1225  1296

which I got by using horrible code:

d <- matrix^2

d[1,3] <- matrix[1,1] * matrix[3,3]
d[1,4] <- matrix[1,2] * matrix[3,4]
d[1,5] <- matrix[1,1] * matrix[5,5]
d[1,6] <- matrix[1,2] * matrix[5,6]
d[2,3] <- matrix[2,1] * matrix[4,3]
d[2,4] <- matrix[2,2] * matrix[4,4]
d[2,5] <- matrix[2,1] * matrix[6,5]
d[2,6] <- matrix[2,2] * matrix[6,6]

d[3,1] <- matrix[3,3] * matrix[1,1]
d[3,2] <- matrix[3,4] * matrix[1,2]
d[3,5] <- matrix[3,3] * matrix[5,5]
d[3,6] <- matrix[3,4] * matrix[5,6]
d[4,1] <- matrix[4,3] * matrix[2,1] 
d[4,2] <- matrix[4,4] * matrix[2,2]
d[4,5] <- matrix[4,3] * matrix[6,5]
d[4,6] <- matrix[4,4] * matrix[6,6]

d[5,1] <- matrix[5,5] * matrix[1,1]
d[5,2] <- matrix[5,6] * matrix[1,2]
d[5,3] <- matrix[5,5] * matrix[3,3]
d[5,4] <- matrix[5,6] * matrix[3,4]
d[6,1] <- matrix[6,5] * matrix[2,1]
d[6,2] <- matrix[6,6] * matrix[2,2]
d[6,3] <- matrix[6,5] * matrix[4,3]
d[6,4] <- matrix[6,6] * matrix[4,4]

Is there a code than can solve this more efficiently with loops or some other way?

like image 981
Adrian Avatar asked Aug 01 '18 15:08

Adrian


People also ask

Why does matrix multiplication row column rule?

To show how many rows and columns a matrix has we often write rows×columns. When we do multiplication: The number of columns of the 1st matrix must equal the number of rows of the 2nd matrix. And the result will have the same number of rows as the 1st matrix, and the same number of columns as the 2nd matrix.

How do you name rows and columns in a matrix?

Naming Rows and Columns of a Matrix in R Programming – rownames() and colnames() Function. rownames() function in R Language is used to set the names to rows of a matrix.

Which corresponds to the column name and row name?

If the object has dimnames the first component is used as the row names, and the second component (if any) is used for the column names. For a data frame, rownames and colnames eventually call row. names and names respectively, but the latter are preferred.

How do I use Colnames?

Method 1: using colnames() method colnames() method in R is used to rename and replace the column names of the data frame in R. The columns of the data frame can be renamed by specifying the new column names as a vector. The new name replaces the corresponding old name of the column in the data frame.


2 Answers

Dirty with loops:

d2 <- matrix^2
for (i in rownames(matrix)) {
  for (j in colnames(matrix)) {
    i1 <- strsplit(i, ' ', fixed = T)[[1]]
    j1 <- strsplit(j, ' ', fixed = T)[[1]]
    ni <- c(i1[2], j1[2])
    n1 <- paste(i1[1], ni)
    n2 <- paste(j1[1], ni)
    d2[i, j] <- matrix[n1[1], n1[2]] * matrix[n2[1], n2[2]]
  }
}

d2
#       aaa 1 aaa 2 bbb 1 bbb 2 ccc 1 ccc 2
# aaa 1     1     4    15    32    29    60
# aaa 2    49    64   147   176   245   288
# bbb 1    15    32   225   256   435   480
# bbb 2   147   176   441   484   735   792
# ccc 1    29    60   435   480   841   900
# ccc 2   245   288   735   792  1225  1296
all.equal(d2, d)
# [1] TRUE

This will be faster (without loops):

require(data.table)
require(Hmisc)
mat <- matrix # rename matrix variable,
# it is bad practice to name variables the same as internal functions
rn <- rownames(mat)
nn <- data.table(expand.grid(rn, rn, stringsAsFactors = F)) # all combinations of names
# split into parts:
nn[, Cs(v1, s1) := tstrsplit(Var1, ' ', fixed = T)]
nn[, Cs(v2, s2) := tstrsplit(Var2, ' ', fixed = T)]

# make respective new names:
nn[, a1 := paste(v1, s1)]
nn[, a2 := paste(v1, s2)]
nn[, b1 := paste(v2, s1)]
nn[, b2 := paste(v2, s2)]

index <- as.matrix(nn[, lapply(.SD, match, rn),
                      .SDcols = Cs(a1, a2, b1, b2)]) # get indexes of elements

d3 <- mat[index[, 1:2]] * mat[index[, 3:4]] # selection of elements and multiplication
d3 <- matrix(d3, ncol = ncol(mat)) # convert to matrix
rownames(d3) <- rn
colnames(d3) <- rn

all.equal(d3, d2)
# [1] TRUE
like image 160
minem Avatar answered Sep 18 '22 08:09

minem


We can use mapply here

#Get all the possible combination of rownames and column names
all_combns <- expand.grid(rownames(matrix), colnames(matrix),
                   stringsAsFactors = FALSE)

matrix[] <- mapply(function(x, y) {
        #Extract first three letters
        first_group <- substr(x, 1, 3)
        second_group <- substr(y, 1, 3)

        #Extract the numeric part which could also be done in this example by
        #substr(x, 5, 5)
        #I am just extracting the numeric part in the string.
        first_num <- sub("[^\\d]+", "", x, perl = TRUE)
        second_num <- sub("[^\\d]+", "", y, perl = TRUE)

        #Construct element 1 and multiply it by elemnt 2
        matrix[paste(first_group, first_num),paste(first_group, second_num)] *
        matrix[paste(second_group, first_num),paste(second_group, second_num)]
        } , all_combns[, 1], all_combns[, 2])

matrix

#      aaa 1 aaa 2 bbb 1 bbb 2 ccc 1 ccc 2
#aaa 1     1     4    15    32    29    60
#aaa 2    49    64   147   176   245   288
#bbb 1    15    32   225   256   435   480
#bbb 2   147   176   441   484   735   792
#ccc 1    29    60   435   480   841   900
#ccc 2   245   288   735   792  1225  1296
like image 32
Ronak Shah Avatar answered Sep 21 '22 08:09

Ronak Shah