Search code examples
rfunctionmatrixsum

Writing a Function That References Elements in a Matrix


I have a data frame called "relations":

library(tidyverse)
library(igraph)


set.seed(123)

n=10
data = tibble(d = paste(1:n))

relations = tibble(
  from = sample(data$d),
  to = lead(from, default=from[1]),
)

relations = data.frame(relations)

The "relations" data frame looks like this:

   from to
1     3 10
2    10  2
3     2  8
4     8  6
5     6  9
6     9  1
7     1  7
8     7  5
9     5  4
10    4  3

I then have a matrix called "m" (the dimensions of this matrix correspond to the "relations" data frame):

m<-matrix(rnorm(100) , nrow = 10)

             [,1]       [,2]        [,3]       [,4]       [,5]       [,6]        [,7]       [,8]        [,9]      [,10]
 [1,] -1.66794194 -0.6407060  0.07796085  0.7399475  0.6879168 -0.3724388 -0.48378063  0.3104807  0.08473729 -1.2512714
 [2,] -0.38022652 -0.8497043 -0.96185663  1.9091036  2.1001089  0.9769734  0.51686204  0.4365235  0.75405379 -0.6111659
 [3,]  0.91899661 -1.0241288 -0.07130809 -1.4438932 -1.2870305 -0.3745809  0.36896453 -0.4583653 -0.49929202 -1.1854801
 [4,] -0.57534696  0.1176466  1.44455086  0.7017843  0.7877388  1.0527115 -0.21538051 -1.0633261  0.21444531  2.1988103
 [5,]  0.60796432 -0.9474746  0.45150405 -0.2621975  0.7690422 -1.0491770  0.06529303  1.2631852 -0.32468591  1.3124130
 [6,] -1.61788271 -0.4905574  0.04123292 -1.5721442  0.3322026 -1.2601552 -0.03406725 -0.3496504  0.09458353 -0.2651451
 [7,] -0.05556197 -0.2560922 -0.42249683 -1.5146677 -1.0083766  3.2410399  2.12845190 -0.8655129 -0.89536336  0.5431941
 [8,]  0.51940720  1.8438620 -2.05324722 -1.6015362 -0.1194526 -0.4168576 -0.74133610 -0.2362796 -1.31080153 -0.4143399
 [9,]  0.30115336 -0.6519499  1.13133721 -0.5309065 -0.2803953  0.2982276 -1.09599627 -0.1971759  1.99721338 -0.4762469
[10,]  0.10567619  0.2353866 -1.46064007 -1.4617556  0.5629895  0.6365697  0.03778840  1.1099203  0.60070882 -0.7886028

I would like to write a function that :

  • selects the element in the matrix "m" corresponding to the "(from,to) numbers" for each row in the "relations" data frame

  • and then sums all these elements together

In my case, this would look something like this:

sums = m[3,10] + m[10,2] + m[2,8] + m[8,6] + m[6,9] + m[9,1] + m[1,7] + m[7,5] + m[5,4] + m[4,3]

 sums

[1] -0.8444946

I thought that perhaps I could "reference" the correct elements in the matrix using the following "trick":

sums = m[relations[1,1], relations[1,2]] + m[relations[2,1], relations[2,2]] + m[relations[3,1], relations[3,2]] + m[relations[4,1], relations[4,2]] + m[relations[5,1], relations[5,2]] + m[relations[6,1], relations[6,2]] + m[relations[7,1], relations[7,2]] + m[relations[8,1], relations[8,2]] + m[relations[9,1], relations[9,2]] + m[relations[10,1], relations[10,2]]

Error in m[relations[1, 1], relations[1, 2]] : subscript out of bounds

I then tried this:

sums = m[as.numeric(relations[1,1]), as.numeric(relations[1,2])] + 
m[as.numeric(relations[2,1]), as.numeric(relations[2,2])] 
+ m[as.numeric(relations[3,1]), as.numeric(relations[3,2])] 
+ m[as.numeric(relations[4,1]), as.numeric(relations[4,2])] 
+ m[as.numeric(relations[5,1]), as.numeric(relations[5,2])] +
 m[as.numeric(relations[6,1]), as.numeric(relations[6,2])] +
 m[as.numeric(relations[7,1]), as.numeric(relations[7,2])] + 
m[as.numeric(relations[8,1]), as.numeric(relations[8,2])] +
 m[as.numeric(relations[9,1]), as.numeric(relations[9,2])] +
 m[as.numeric(relations[10,1]), as.numeric(relations[10,2])]

        X9 
0.08593303 

Although I think of made a mistake, because the

-0.8444946 <> 0.08593303 

How can I write a function that that automatically performs the following operation for any "relations" and "m"?

sums = m[3,10] + m[10,2] + m[2,8] + m[8,6] + m[6,9] + m[9,1] + m[1,7] + m[7,5] + m[5,4] + m[4,3]

Thank you!


Solution

  • You can index a matrix m using [ and another matrix with columns corresponding to the rows and columns of m, just like your relations object. So all we need to do is covert relations to matrix, use it to index m, and sum it all:

    my_sums = function(relations, m) {
      r = as.matrix(relations)
      if(mode(r) != "numeric") mode(r) = "numeric"
      sum(m[r])
    }
    
    my_sums(relations, m)
    

    (Untested since you didn't share an m, but should work fine.)