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?
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.
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.
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.
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.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With