Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Creating a matrix containing the minimum element-by-element value from other matrices

    Hello. I am trying to create a new matrix in which each element is definied as the minimal value of the elements in the corresponding location from other matrices. I'm using Stata16, and My actual matrices contains roughly 35000 rows and 35000 collumms. For the examples here I define matrices A and B which are 3 X 3, and the result I'm looking for is matrix C
    Code:
    . mata
    : // Define matrices
    : A = (1 , 2 , . \ 4 , 5 , 6 \ . , 8 , 9)
    
    : B = (3 , 4 , 7 \ 2 , . , . \ 1 , 8 , 2)
    
    : C = (1 , 2 , 7 \ 2 , 5 , 6 \ 1 , 8 , 2)
    
    : 
    : // Matrix A
    : A
           1   2   3
        +-------------+
      1 |  1   2   .  |
      2 |  4   5   6  |
      3 |  .   8   9  |
        +-------------+
    
    : // Matrix B
    : B
           1   2   3
        +-------------+
      1 |  3   4   7  |
      2 |  2   .   .  |
      3 |  1   8   2  |
        +-------------+
    
    : // Desired Matrix C
    : C
           1   2   3
        +-------------+
      1 |  1   2   7  |
      2 |  2   5   6  |
      3 |  1   8   2  |
        +-------------+
    : end
    I know of two ways to approach this problem, one is working element by element, e.g:
    Code:
    . mata
    : C = A
    
    : for (i=1; i<=3; i++) {
    >         for (j=1; j<=3; j++) {
    >                 if (B[i,j] < A[i,j]) (C[i,j] = B[i,j])
    >         }
    > }
    
    : C
           1   2   3
        +-------------+
      1 |  1   2   7  |
      2 |  2   5   6  |
      3 |  1   8   2  |
        +-------------+
    
    : end
    This approach returns the desired result but is very expensive computationally. The other approach uses a logical condition to create the matrix, e.g:
    Code:
    . mata
    : C = J(3,3,.)            
    
    : C = A:* (A:<B) + B:* (B:<=A)
    
    : C
           1   2   3
        +-------------+
      1 |  1   2   .  |
      2 |  2   .   .  |
      3 |  .   8   2  |
        +-------------+
    
    : end
    This approach is more efficent, but dosen't handle cells with missing values (since 0 times a missing value equals missing value).

    I'm looking for an approach that would be computationally efficent (since as mentioned above I'm working with large matrices), and would return the desired result even when encountering missing values. Would appreciate any advice.

    Nir.

  • #2
    This seems to do what I think you want. Thank you for the entertaining brain teaser.
    Code:
    : // Define matrices - note that [3,1] now missing in both A and B
    : A = (1 , 2 , . \ 4 , 5 , 6 \ . , 8 , 9)
    
    : B = (3 , 4 , 7 \ 2 , . , . \ . , 8 , 2)
    
    : C = (1 , 2 , 7 \ 2 , 5 , 6 \ . , 8 , 2)
    
    : // Matrix A
    : A
           1   2   3
        +-------------+
      1 |  1   2   .  |
      2 |  4   5   6  |
      3 |  .   8   9  |
        +-------------+
    
    : // Matrix B
    : B
           1   2   3
        +-------------+
      1 |  3   4   7  |
      2 |  2   .   .  |
      3 |  .   8   2  |
        +-------------+
    
    : // Desired Matrix C
    : C
           1   2   3
        +-------------+
      1 |  1   2   7  |
      2 |  2   5   6  |
      3 |  .   8   2  |
        +-------------+
    
    : // everything except for cells with both missing 
    : E = editmissing(A,0) :* (A:<B) + editmissing(B,0) :* (B:<=A)
    
    : E
           1   2   3
        +-------------+
      1 |  1   2   7  |
      2 |  2   5   6  |
      3 |  0   8   2  |
        +-------------+
    
    : // locate cells with both missing
    : F = (.:==A) :& (.:==B)
    
    : F
           1   2   3
        +-------------+
      1 |  0   0   0  |
      2 |  0   0   0  |
      3 |  1   0   0  |
        +-------------+
    
    : E = E + editvalue(F,1,.)
    
    : E
           1   2   3
        +-------------+
      1 |  1   2   7  |
      2 |  2   5   6  |
      3 |  .   8   2  |
        +-------------+
    
    : // and to remind us of the objective
    : C
           1   2   3
        +-------------+
      1 |  1   2   7  |
      2 |  2   5   6  |
      3 |  .   8   2  |
        +-------------+
    
    : // as a single command
    : D = editmissing(A,0):*(A:<B) + editmissing(B,0):*(B:<=A) + editvalue((.:==A):&(.:==B),1,.)
    
    : D
           1   2   3
        +-------------+
      1 |  1   2   7  |
      2 |  2   5   6  |
      3 |  .   8   2  |
        +-------------+
    
    : 
    : end

    Comment


    • #3
      Hello William. Thank you for your helpful reply. For future refrence I'd point out that William's solution works and vastly improves preformance compared to the element by element solution displayed above. I currently use another solution. At first, I edit all missing values in the matrices to be larger then the maximal value in any element inside them, I then proceed as if there were no missing values in the matrices, e.g (corresponding to William's single command row:
      : D = A:*(A:<B) + B:*(B:<=A)
      For my specific use (Floyd Warshall algorithm with large (34621 X 34621) and sparse matrices), this solution is even more efficent then William's.

      Comment

      Working...
      X