Announcement

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

  • Cumulative rowsum - problem with 0s: want to keep them in the cumulative matrix

    Dear Statalist,

    I've been having an issue with the cumulative running sum (by row). I have a matrix X that is made of positive numbers and some 0s. My goal is to have the cumulative rowsum, but when it encounters a 0, to replace the matrix with a 0. Instead, of course, Mata is just replacing the matrix by the last sum+0.

    Let me show an example:

    Original matrix

    . mata: x
    1 2 3
    +-------------------+
    1 | 150 0 10 |
    2 | 10 0 0 |
    3 | 0 10 10 |
    +-------------------+

    GOAL: what I want the cumulative matrix to look like

    1 2 3
    +-------------------+
    1 | 150 0 160 |
    2 | 10 0 0 |
    3 | 0 10 20 |
    +-------------------+


    Code:

    mata: x = (150, 0, 10 \ 10, 0, 0 \ 0, 10, 10 )
    mata: x_c_goal= (150, 0, 160 \ 10, 0, 0 \ 0, 10, 20 )
    mata: nr = rows(x)
    mata: nc = cols(x)


    I'm very new to Mata and the if commands, but I tried doing an if/else and telling it to perform the running sum when it encountered a value higher than 0, or else just assign the original value (0) inside the new matrix. See below:


    mata: x_c = J(nr,nc,0)
    mata: if x[j,]>0 for (j=1;j<=nr;j++) x_c[j,] = runningsum(x[j,],)
    else for (j=1;j<=nr;j++) x_c[j,] = x[j,]


    But this doesn't work and gives the error "'x' found where '(' expected".


    Does someone know how to resolve this problem?

    I know that if I were to replace 0s by missing, and then putting the "1" option in the runningsum(), then it wouldn't perform the running sum where it encounters missings. However, this means that it doesn't perform the sum also for the values in the columns after that..i.e. it gives this result


    . mata: x
    1 2 3
    +-------------------+
    1 | 150 . 10 |
    2 | 10 . . |
    3 | . 10 10 |
    +-------------------+


    . mata: x_c

    1 2 3
    +-------------------+
    1 | 150 . . |
    2 | 10 . . |
    3 | . . . |
    +-------------------+

    And this is not what I want...

    I hope I was clear enough...thanks a lot for your help!




    Alessandra Stampi-Bombelli
    Research Assistant
    University of Zurich

  • #2
    Hi Sandra,

    You're very right that you want to make use of if/else statements (although here because the matrix is initialised to contain 0's, you can actually ditch the else part if you formulate it correctly).

    A couple of things worth noting. Firstly, you only need to enter "mata:" once at the very start. And secondly, you want the if statement on the inside of the for loop, as you're checking the conditions while looping over the rows/columns.

    In all, what you want is the following I believe

    Code:
    mata:
    
    x        = (150, 0, 10 \ 10, 0, 0 \ 0, 10, 10 )
    x_c_goal = (150, 0, 160 \ 10, 0, 0 \ 0, 10, 20 )
    nr       = rows(x)
    nc       = cols(x)
    x_c      = J(nr, nc, 0)
    for (i = 1; i <= nr; i++) {
      for (j = 1; j <= nc; j++) {
        if (x[i, j] != 0) {
          x_c[i, j] = runningsum(x[i, 1::j])[j]
        }
      }
    }
    
    end

    Comment


    • #3
      Perform a running sum first and then replace the required entries with 0's based on the original matrix:

      Code:
      mata:
      
      x = 150, 0, 10 \ 10, 0, 0 \ 0, 10, 10
      
      n = rows(x)
      k = cols(x)
      y = J(n,k,.)
      
      for (i=1; i<=n; i++) {
          y[i,.] = runningsum(x[i,.])
      }
      
      y[.,.] = y:*(x:>0)
      
      end

      Comment

      Working...
      X