Announcement

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

  • Mata fine in .do file, not fine when in program / .ado file

    With acknowledgement to this post (http://stackoverflow.com/questions/1...ith-zeros?lq=1), without which I would never have gotten this far, I ask for help. I am new to the Mata side of Stata and, honestly, am sort of bumbling my way through.

    I need to adapt the code from the above linked post in a loop. (Looping through levels of a variable indicating group membership). Short description--the post shows a solution to populate a matrix in cases where there are 0 observations for one of the response options when using svy, drawing on the results of estpost svy, tab: (estpost from SSC). For my purposes, I will eventually put the contents of the matrix into an Excel file. (The putexcel code is not an issue, thus I did not include it below).

    I can get the Mata code to run when included in the do file (minus "matrixtabzero, cat(4) and not in a loop). Once I move it into the .ado file and a program, I start having problems. Among the many errors I've seen as I have tried things to work out the problem--the argument value (4 in the code below) isn't making it to Mata. Subsequently, there is no matrix for st_matrix to send back to Stata.

    After many google searches, consultations with Intro to Stata Programming, etc., where is my mistake? Alternate suggestions to get to the same end? I should add that people in my office who are beginning Stata users will need to use this, thus I am trying to get to a solution that will be the least confusing for them to run.

    Thank you,
    Julie

    .do file:
    Code:
    estpost svy: tab Q27_15 if DistrictID==4,  se
    
    matrixtabzero, cat(4)
    
    // code for putexcel not shown
    .ado file
    Code:
    program matrixtabzero
        version 14
        syntax , cat(integer)
        mata: mf_matrixtabzero(`cat')
        mata: st_matrix("totmat", d)
    
    end
    
    mata:
    
        real matrix mf_matrixtabzero(real scalar cat) {
    
        real matrix d
        real matrix d1
        real matrix d2
        
        /* count rows, add one for totals row
        assign the category for that row as .a */
        r = (st_matrix("e(Row)"), .a)'
        ct = st_matrix("e(count)")'
        obs = st_matrix("e(obs)")'
        b = st_matrix("e(b)")'
        serr = st_matrix("e(se)")'
        lb = st_matrix("e(lb)")'
        ub = st_matrix("e(ub)")'
    
        d1 = (r , obs, ct, b, serr, lb, ub)
    
        /*  Where there are no totals, use a standard missing value */
        d1[rows(d1),5::7] = J(1,3, .)
    
        /* Check if there are no missing rows.
        If so, output the original returned matrices */
        if (`e(r)' ==cat) d = d1
     
        /* Else create a zero matrix and populate it
        with statistics for the non-missing categories*/
        else {
            d2= J(cat,7,0)
            d2[.,1] =(1::cat)
                for (j = 1; j<=`e(r)'; j++) {
                    for (k = 1; k<=r[j,1]; k++) {
                        if (r[j,1]== k) {
                        d2[k,2] = obs[j,1]
                        d2[k,3] = ct[j,1]
                        d2[k,4] = b[j,1]
                        d2[k,5] = serr[j,1]
                        d2[k,6] = lb[j,1]
                        d2[k,7] = ub[j,1]
                        }
                    }
                }
     
     /* If rows are missing set SE-realated stats to missing     */
                    for (k = 1; k<=cat; k++) {
                        if (d2[k,5] == 0)  d2[k,5..7] =J(1,3,.)
                    }
     /* Now add the totals row  */
            d = d2 \ d1[rows(d1),.]
            st_matrix("totmat", d)
    
        }
    }
    
    
    end
    
    mata: mata mosave mf_matrixtabzero(), dir(PERSONAL) replace

  • #2
    I cannot reproduce your program as it is. There are things in your program which depend on your data (which we don't have). The svy option for example has to be set up correctly. The se option seems also be dependent on the svy set up. So I have to guess where the error lies. It would be helpful if you could make an example with the auto dataset (or any other dataset delivered with Stata) and show us exactly where the program doesn't work. From the link you mention I could retrieve these line of codes to get something similar to your code

    Code:
     sysuse auto, clear
     drop if rep78==2 |rep78==5
    
     svyset _n [pw = turn]
     estpost svy: tab rep78,  se
    that being said one line which is problematic is this one

    Code:
    if (`e(r)' ==cat) d = d1
    When compiling the mata function the local e(r) will either empty or equal to the value its value at compile time, which I guess is not desired. e(r) will likely change each time you run estpost.

    So I would change to
    Code:
    if (st_numscalar("e(r)") ==cat) d = d1
    Similarly you should code

    Code:
    for (j = 1; j<=st_numscalar("e(r)"); j++)
    With these two changes the code seems to work
    Hope this helps

    Comment


    • #3
      Thank you! That would have been a problem in the future... (I am learning).

      And it led me to find another critical error in the code. Specifically, [CODE] st_matrix("totmat", d) was inside the else statement, so if there were no missing rows, the matrix never got sent over to Stata.

      Comment


      • #4
        I can't claim an understanding of your programs, but looking at them structurally, I note that your ado file as shown above includes at the very end a mata movsave command not part of a program. This will get executed just once, when the ado file is processed before the first time matrixtabzero is run, but not again on future invocations. Is this the behavior you have planned on?
        Code:
        . type foo.ado
        program foo
        noisily display "foo notice"
        end
        
        noisily display "bar notice"
        
        . foo
        bar notice
        foo notice
        
        . foo
        foo notice
        
        .

        Comment


        • #5
          Something I forgot to mention and which came to me by reading William's post. I ran your program in a do-file so i overlooked the fact that it is intended to an ado-file. Either you put your code in another file than the ado-file and compile the function with mosave OR you write your ado-file and the mata code afterwards without mosave. The function will then be compiled on the fly when you invoke your ado-file and it will only be accessible to your program. That is the function is not accessible outside the program. I guess it is fine for your purpose.

          Comment

          Working...
          X