Announcement

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

  • Getting a tabulation of comparable variables in one table

    I have a series of Likert variables and I'm trying to get a tabulation of all of them in a single table and have control over the labels. If I use a simple tabm command, I get all labels:
    Code:
    . tabm inc1w1 inc2w1 inc3w1 inc4w1 inc5w1 inc6w1, valuelabel(toseven)
    
                          |                                    values
                 variable | Very inac  Moderatel  A little   Neutral (  A little   Moderatel  Very accu |     Total
    ----------------------+-----------------------------------------------------------------------------+----------
    In the past seven day |         3          0          5          1         10         80        129 |       228 
    In the past seven day |         2          1          1          8         10         74        132 |       228 
    In the past seven day |         3          2          1          3         19         65        134 |       227 
    In the past seven day |         3          1          2         14         21         64        123 |       228 
    In the past seven day |         3          1          0         12         15         76        121 |       228 
    In the past seven day |         2          0          1         14         21         67        123 |       228 
    ----------------------+-----------------------------------------------------------------------------+----------
                    Total |        16          5         10         52         96        426        762 |     1,367
    If I try to define labels for the upper set, nothing happens. This produces the same output as above.

    Code:
    label define toseven 1 "1" 2 "2" 3 "3" 4 "4" 5 "5" 6 "6" 7 "7"
    tabm inc1w1 inc2w1 inc3w1 inc4w1 inc5w1 inc6w1, valuelabel(toseven)
    If I use the nolabel option, the table has integers instead of variable names on the left side. I don't know why it does this when I didn't specify erasing a name but rather a label.


    Code:
    . tabm inc1w1 inc2w1 inc3w1 inc4w1 inc5w1 inc6w1, nolabel
    
               |                                    values
      variable |         1          2          3          4          5          6          7 |     Total
    -----------+-----------------------------------------------------------------------------+----------
             1 |         3          0          5          1         10         80        129 |       228 
             2 |         2          1          1          8         10         74        132 |       228 
             3 |         3          2          1          3         19         65        134 |       227 
             4 |         3          1          2         14         21         64        123 |       228 
             5 |         3          1          0         12         15         76        121 |       228 
             6 |         2          0          1         14         21         67        123 |       228 
    -----------+-----------------------------------------------------------------------------+----------
         Total |        16          5         10         52         96        426        762 |     1,367 
    
    .

    What I'd like to get is this:

    Code:
    . tabm inc1w1 inc2w1 inc3w1 inc4w1 inc5w1 inc6w1, nolabel
    
               |                                    values
      variable |         1          2          3          4          5          6          7 |     Total
    -----------+-----------------------------------------------------------------------------+----------
       inc1w1 |         3          0          5          1         10         80        129 |       228 
       inc1w2 |         2          1          1          8         10         74        132 |       228 
       inc1w3 |         3          2          1          3         19         65        134 |       227 
       inc1w4 |         3          1          2         14         21         64        123 |       228
       inc1w5 |         3          1          0         12         15         76        121 |       228 
       inc1w6 |         2          0          1         14         21         67        123 |       228 
    -----------+-----------------------------------------------------------------------------+----------
         Total |        16          5         10         52         96        426        762 |     1,367 
    
    .

  • #2
    tabm is from tab_chi on SSC. (People new to a command can be bemused not to find it in their Stata, so we ask that you explain the provenance of community-contributed commands: FAQ Advice #12.)

    You found a bug lurking since at least 2016. nolabel is just an option passed by the command to tabulate and does what it is supposed to do. That's part of official Stata. But valuelabel() is a legal option yet ignored because the code currently on SSC is only on the lookout for vallbl(). I guess I intended to make the option name less cryptic, or less Klingon-seeming, but got distracted, for whatever reason. Sorry about that.

    The example below runs as intended, provided you use the code as revised further below.


    Code:
    clear 
    set obs 100 
    set seed 2803 
    label def whatever 1 appalling 2 banal 3 charming 
    forval j = 1/6 {
        gen inc`j'w1 = runiformint(1, 3)
        label val inc`j'w1 whatever 
    }
    
    tabm inc*w1 
    
    label def show 1 "1" 2 "2" 3 "3"
    
    tabm inc*w1, valuelabel(show)
    
               |              values
      variable |         1          2          3 |     Total
    -----------+---------------------------------+----------
        inc1w1 |        35         32         33 |       100 
        inc2w1 |        30         29         41 |       100 
        inc3w1 |        27         28         45 |       100 
        inc4w1 |        37         30         33 |       100 
        inc5w1 |        38         25         37 |       100 
        inc6w1 |        30         30         40 |       100 
    -----------+---------------------------------+----------
         Total |       197        174        229 |       600 
    
    .
    Code:
    *! 2.2.2 NJC 6 May 2021
    *! 2.2.1 NJC 20 December 2016
    * 2.2.0 NJC 31 March 2016
    * 2.1.0 NJC 25 July 2015
    * 2.0.0 NJC 1 November 2010
    * 1.4.0 NJC 4 November 2005
    * 1.3.1 NJC 11 December 2002
    * 1.3.0 NJC 10 December 2002
    * 1.2.0 NJC 5 February 1999
    * 1.0.0 NJC 22 December 1998
    program tabm, byable(recall)
        version 8.2
        syntax varlist(min=2) [if] [in] [fw aw iw] ///
        [, ONEway transpose Valuelabel(string) MISSing replace *]
    
        marksample touse, novarlist
    
        if "`replace'" != "" & _by() {
            di as err "replace not allowed with by:"
            exit 198
        }
    
        qui count if `touse'
        if r(N) == 0 error 2000
    
        if "`exp'" != "" {
            tempvar wt
            gen `wt' `exp'
            local w "[`weight' = `wt']"
        }
    
        capture confirm string variable `: word 1 of `varlist''
        local strOK = _rc == 0
        local j = 1
        foreach v of local varlist {
            capture confirm string variable `v'
            if (`strOK' & _rc == 0) | (!`strOK' & _rc) {
                local OKlist `OKlist' `v'
                local slist `slist' `v' `wt'
                local lbl`j' : variable label `v'
                if `"`lbl`j''"' == "" local lbl`j' "`v'"
                local ++j
            }
            else local badlist `badlist' `v'  
        }
    
        if "`badlist'" != "" {
            di _n "{res}`badlist' {txt}different type, so excluded"
        }
    
        local nvars : word count `OKlist'
        // normal tabulation, no need to stack
        if `nvars' == 1 {
            tab `OKlist' `w', `missing' `options'
            exit 0
        }
    
        if "`valuelabel'" == "" {
            local 1 : word 1 of `slist'
            local valuelabel : value label `1'
        }
        // insurance policy
        if "`valuelabel'" != "" {
            tempfile flabels
            qui label save `valuelabel' using `"`flabels'"'
        }
    
        preserve
        tempvar data
        stack `slist' if `touse', into(`data' `wt') clear
        label var _stack "variable"
        label var `data' "values"
        forval i = 1 / `nvars' {
            label def _stack `i' `"`lbl`i''"', add
        }
        label val _stack _stack
    
        if "`valuelabel'" != "" {
            if `strOK' di _n as txt "may not label strings"
            else {
                capture label list `valuelabel'
                if _rc run `flabels'
                label val `data' `valuelabel'
            }
        }
    
        if "`oneway'" != "" {
            tab `data' `w', `missing' `options'
        }
        else {
            if "`transpose'" == "" {
                tab _stack `data' `w', `missing' `options'
            }
            else tab `data' _stack `w' , `missing' `options'
        }
    
        if "`replace'" != "" {
            clonevar _values = `data'
            if "`w'" != "" {
                clonevar _weight = `wt'
                label var _weight "weights"
            }
            restore, not
        }
    end

    Comment


    • #3
      Thanks. This worked for the table contents. Is there a way to control whether the variable label or variable name displays on the leftmost column? Currently, I get the variable label.

      Comment


      • #4
        You can insist on that with the varnames option added below.

        Code:
        *! 2.3.0 NJC 6 May 2021
        * 2.2.2 NJC 6 May 2021
        * 2.2.1 NJC 20 December 2016
        * 2.2.0 NJC 31 March 2016
        * 2.1.0 NJC 25 July 2015
        * 2.0.0 NJC 1 November 2010
        * 1.4.0 NJC 4 November 2005
        * 1.3.1 NJC 11 December 2002
        * 1.3.0 NJC 10 December 2002
        * 1.2.0 NJC 5 February 1999
        * 1.0.0 NJC 22 December 1998
        program tabm, byable(recall)
            version 8.2
            syntax varlist(min=2) [if] [in] [fw aw iw] ///
            [, ONEway transpose Valuelabel(string) VARNAMEs MISSing replace *]
        
            marksample touse, novarlist
        
            if "`replace'" != "" & _by() {
                di as err "replace not allowed with by:"
                exit 198
            }
        
            qui count if `touse'
            if r(N) == 0 error 2000
        
            if "`exp'" != "" {
                tempvar wt
                gen `wt' `exp'
                local w "[`weight' = `wt']"
            }
        
            capture confirm string variable `: word 1 of `varlist''
            local strOK = _rc == 0
            local j = 1
            foreach v of local varlist {
                capture confirm string variable `v'
                if (`strOK' & _rc == 0) | (!`strOK' & _rc) {
                    local OKlist `OKlist' `v'
                    local slist `slist' `v' `wt'
                    local lbl`j' : variable label `v'
                    if "`varnames'" != "" | `"`lbl`j''"' == "" {
                        local lbl`j' "`v'"
                    } 
                    local ++j
                }
                else local badlist `badlist' `v'  
            }
        
            if "`badlist'" != "" {
                di _n "{res}`badlist' {txt}different type, so excluded"
            }
        
            local nvars : word count `OKlist'
            // normal tabulation, no need to stack
            if `nvars' == 1 {
                tab `OKlist' `w', `missing' `options'
                exit 0
            }
        
            if "`valuelabel'" == "" {
                local 1 : word 1 of `slist'
                local valuelabel : value label `1'
            }
            // insurance policy
            if "`valuelabel'" != "" {
                tempfile flabels
                qui label save `valuelabel' using `"`flabels'"'
            }
        
            preserve
            tempvar data
            stack `slist' if `touse', into(`data' `wt') clear
            label var _stack "variable"
            label var `data' "values"
            forval i = 1 / `nvars' {
                label def _stack `i' `"`lbl`i''"', add
            }
            label val _stack _stack
        
            if "`valuelabel'" != "" {
                if `strOK' di _n as txt "may not label strings"
                else {
                    capture label list `valuelabel'
                    if _rc run `flabels'
                    label val `data' `valuelabel'
                }
            }
        
            if "`oneway'" != "" {
                tab `data' `w', `missing' `options'
            }
            else {
                if "`transpose'" == "" {
                    tab _stack `data' `w', `missing' `options'
                }
                else tab `data' _stack `w' , `missing' `options'
            }
        
            if "`replace'" != "" {
                clonevar _values = `data'
                if "`w'" != "" {
                    clonevar _weight = `wt'
                    label var _weight "weights"
                }
                restore, not
            }
        end

        Comment


        • #5
          Thanks! I'm now trying to figure out why these don't work. I'm listing all four variations that I've tried

          Code:
          tabm match_vars
          tabm `match_vars'
          tabm local `match_vars'
          tabm local match_vars

          Comment


          • #6
            I wouldn't expect tabm local to work unless local is the name of a variable. As for


            Code:
             
             tabm `match_vars'
            what is in the local macro match_vars ?

            Comment


            • #7
              Here's the full code. It's a macro created with a regular expression. Leonardo Guizzetti created it

              Code:
              * create a macro with all inc items but exclude incgw incwk -- doesn't really work with tabm though
              local match_vars
              forval i = 1/`: word count `vars'' {
                  local v : word `i' of `vars'
                  if ustrregexm("`v'", "inc[0-9]w[0-9]", .) {
                    local match_vars `match_vars' `v'
                }  
              }
              tabm `match_vars'

              Comment


              • #8
                OK, so that should yield a local macro containing those variables with names inc?w? where each ? must be a digit 0 to 9. "doesn't really work" is a not a problem report I can respond to it easily.

                What is in local macro just before you call tabm?

                Code:
                di "`match_vars'"
                Does tabm give you no table or a table that is not what you want or expect?

                Comment


                • #9
                  Sorry. This is the input and output. There is no error as such but also no output.

                  Code:
                  . * create a macro with all inc items but exclude incgw incwk -- doesn't really work with tabm though
                  . local match_vars
                  
                  . forval i = 1/`: word count `vars'' {
                    2.     local v : word `i' of `vars'
                    3.     if ustrregexm("`v'", "inc[0-9]w[0-9]", .) {
                    4.       local match_vars `match_vars' `v'
                    5.   }  
                    6. }
                  
                  . di "`match_vars'"

                  Comment


                  • #10
                    That is from this thread: https://www.statalist.org/forums/for...kert-variables

                    Also tabm gives the error: varlist required r(100);

                    Comment


                    • #11
                      Evidently the local macro match_vars is empty, which could arise in at least two ways:

                      1. No variables in your dataset match the given pattern.

                      2. You are running code line by line or in small chunks so that the definition of match_vars is hidden from any command that tries to use it. All the code needs to be run at once.

                      It's not the fault of tabm if it produces no output given no input, which is the error message you cite.

                      Comment


                      • #12
                        There are variables with names like inc1w1 in the dataset and I'm running the whole chunk of code at once. I suspect there's some issue with this block of code although I have no idea what:
                        Code:
                        * create a macro with all inc items but exclude incgw incwk -- doesn't really work with tabm though
                        local match_vars
                        forval i = 1/`: word count `vars'' {
                            local v : word `i' of `vars'
                            if ustrregexm("`v'", "inc[0-9]w[0-9]", .) {
                              local match_vars `match_vars' `v'
                          }  
                        }
                        Anyway I found two workarounds:
                        Code:
                        *first method -- make sure you use the tabm.ado file from statalist thread above
                        tabm inc1w1 inc2w1 inc3w1 inc4w1 inc5w1 inc6w1 ///
                          inc1w2 inc2w2 inc3w2 inc4w2 inc5w2 inc6w2 ///
                          inc1w3 inc2w3 inc3w3 inc4w3 inc5w3 inc6w3 ///
                          inc1w4 inc2w4 inc3w4 inc4w4 inc5w4 inc6w4 ///
                          inc1w5 inc2w5 inc3w5 inc4w5 inc5w5 inc6w5, valuelabel(toseven) varnames
                        * second method
                        forvalues j = 1(1)5 {
                        forvalues i = 1(1)6 {
                        qui gen incl_it`i'_w`j' =  inc`i'w`j'
                        }
                        }
                        tabm incl_it*

                        Comment


                        • #13
                          Where do you define local vars ?

                          Comment


                          • #14
                            Ah that was the problem. This works:
                            Code:
                            * create a macro with all inc items but exclude incgw incwk -- doesn't really work with tabm though
                            qui ds
                            local vars `r(varlist)'
                            local match_vars
                            forval i = 1/`: word count `vars'' {
                                local v : word `i' of `vars'
                                if ustrregexm("`v'", "inc[0-9]w[0-9]", .) {
                                  local match_vars `match_vars' `v'
                              }
                            }
                            . tabm `match_vars', valuelabel(toseven) varnames

                            Comment


                            • #15
                              For those interested, asdocx has a tabmany sub-command which tabulates many similar variables in one table. This Statalist post has relevant details https://www.statalist.org/forums/for...es-using-asdoc
                              Regards
                              --------------------------------------------------
                              Attaullah Shah, PhD.
                              Professor of Finance, Institute of Management Sciences Peshawar, Pakistan
                              FinTechProfessor.com
                              https://asdocx.com
                              Check out my asdoc program, which sends outputs to MS Word.
                              For more flexibility, consider using asdocx which can send Stata outputs to MS Word, Excel, LaTeX, or HTML.

                              Comment

                              Working...
                              X