Announcement

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

  • replacing the diagonal elements in a matrix with those of a single column (row) in another matrix

    Hi All,

    I would like to replace the diagonal elements of the matrix (ZZ below) with the values that are in the Z matrix (which are in a row).

    Code:
    matrix Z = (3883, 4478, 4963)
    matrix ZZ = (1520, 0, 0 \ 0, 1512, 0 \ 0, 0, 1772)
    I saw in the help file for mata there appears some way to use _diag() for this, but I don't know mata, and Stata keeps shutting down when I try to apply it...

    Thanks in advance!

    Ariel

  • #2
    As you have already noticed, matrix manipulation is much more convenient in Mata. If you want to stick with Stata and have readable syntax, you can always simply loop over the elements.

    Something like this should work (I am typing this on my smartphone so there might be typos or other problems):

    Code:
    local ndiag = colsof(ZZ)
    local ncols = colsof(Z)
    
    assert `ndiag' == `ncols'
    
    forvalues i = 1/`ncols' {
        matrix ZZ[`i', `i'] = Z[`i']
    }
    btw. you might want to check whether ZZ is symmetric and you probably want nicer error messages if there is a conformability error
    Last edited by daniel klein; 21 Jul 2023, 14:14.

    Comment


    • #3
      Hey Ariel, just so I get what you're asking, could you give your intended result? I think I understand, I just want to be sure.


      EDIT: Is this the result you'd expected?

      Code:
      clear *
      
      matrix Z = (3883, 4478, 4963)
      matrix ZZ = (1520, 0, 0 \ 0, 1512, 0 \ 0, 0, 1772)
      
      local ndiag = colsof(ZZ)
      local ncols = colsof(Z)
      
      assert `ndiag' == `ncols'
      
      forvalues i = 1/`ncols' {
          matrix ZZ[`i', `i'] = Z[1, `i']
      }
      cls
      mat l ZZ
      Last edited by Jared Greathouse; 21 Jul 2023, 14:21.

      Comment


      • #4
        For your example in #1, -diag()- is sufficient, but the following sequence is a general solution (example modified). The matrices must be conformable.

        Code:
        matrix Z = (3883, 4478, 4963)
        matrix ZZ = (1520, 1, 2 \ 3, 1512, 1 \ 2, 3, 1772)
        mat wanted= ZZ- diag(vecdiag(ZZ))+ diag(Z)
        mat l Z
        mat l ZZ
        mat l wanted
        Res.:

        Code:
        . mat wanted= ZZ- diag(vecdiag(ZZ))+ diag(Z)
        
        . 
        . mat l Z
        
        Z[1,3]
              c1    c2    c3
        r1  3883  4478  4963
        
        . 
        . mat l ZZ
        
        ZZ[3,3]
              c1    c2    c3
        r1  1520     1     2
        r2     3  1512     1
        r3     2     3  1772
        
        . 
        . mat l wanted
        
        wanted[3,3]
              c1    c2    c3
        c1  3883     1     2
        c2     3  4478     1
        c3     2     3  4963
        
        .

        Comment


        • #5
          If ZZ is only a diagonal matrix:

          Code:
          . matrix Z = (3883, 4478, 4963)
          
          . matrix ZZ = (1520, 0, 0 \ 0, 1512, 0 \ 0, 0, 1772)
          
          . mat ZZ2 = inv(ZZ)*ZZ*diag(Z)
          
          . mat list ZZ
          
          symmetric ZZ[3,3]
                c1    c2    c3
          r1  1520
          r2     0  1512
          r3     0     0  1772
          
          . mat list ZZ2
          
          symmetric ZZ2[3,3]
                c1    c2    c3
          c1  3883
          c2     0  4478
          c3     0     0  4963
          Or more generally:
          Code:
          matrix Z = (3883, 4478, 4963)
          matrix ZZ = (1520, 5, 6 \ 0, 1512, 0 \ 1, 0, 1772)
          
          mat a = ZZ - diag(vecdiag(ZZ))
          mat ZZ2 = inv(ZZ)*ZZ*diag(Z) +ZZ - diag(vecdiag(ZZ))
          mat list ZZ2

          Comment


          • #6
            Thank you, Scott! It works perfectly!

            Comment

            Working...
            X