Announcement

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

  • Identify value label names and storing in macro

    Dear All,

    I have a dataset imported into STATA. While importing, variable names get changed to lowercase but their value label names stay as is.

    For example, I have a variable v012a but its value labels (lblname) are defined as V012A. I want to define v012a's own labels by copying labels values from V012A. There are thousands of such mismatches so it is extremely time consuming to do the following manually for each variable:

    1. describe v012a
    2. Identify vallab (V012A in this case)
    3. label copy V012A v012a
    4. label value v012a v012a

    Is there any solution to achieve this for each variable in one go? I tried writing the following program but it is taking too much time to execute:

    -----------------------------
    program labelfix
    version 12
    syntax [varlist]


    local vars `"`varlist'"'

    // create list of variables for modification
    local finalvars
    foreach var of varlist `vars' {
    cap la li `var'
    if _rc {
    local finalvars "`finalvars' `var'"
    di in green "no value labels defined for `var'"
    }
    else {
    di in green "value labels for `var' already defined. no change"
    }
    }

    // label variables
    cap la dir
    local labels `"`r(names)'"'
    foreach varlab of local labels {
    preserve
    uselabel, clear var
    local newvarlist `"`r(`varlab')'"'
    restore
    if "`newvarlist'" != "" {
    foreach var of varlist `newvarlist' {
    if ("`varlab'" != "`var'" & strpos(`"`finalvars'"', "`var'") != 0) {
    la copy `varlab' `var', replace
    }
    }
    qui save "$S_FN", replace
    }
    }

    cap la dir
    local labels `"`r(names)'"'
    foreach var of local labels {
    la val `var' `var'
    }
    qui save "$S_FN", replace

    end
    --------------------------

    Thanks for help.

    Regards

  • #2
    See elabel (SSC). Will post back giving more details later.

    Comment


    • #3
      I think you can do this as follows:
      Code:
      ds, has(vallabel)
      local labeled_vars `r(varlist)'
      
      foreach v of local labeled_vars {
          local lbl: value label `v'
          local newname = lower(`"`lbl'"')
          elabel rename `lbl' `newname'    
      }
      -elabel- is written by Dan Klein and is available from SSC. (It also has several other handy subcommands for label management.)

      Added: Crossed with #2.

      Comment


      • #4
        Thanks Dan and Clyde. -elabel- is very useful in my case and Clyde's code is perfectly working. Appreciate your help!

        However, I wrote the following code after posting my query and unlike my previous code, is running very fast. Added advantage is that even if the mismatch in varname and lblname is beyond upper/lowercase type of mismatch, this code should work. I hope you don't see any bug/problem with this?

        Code:
        program labelfix
         version 12
         syntax [varlist]
        
        
        preserve
        describe, replace
        local varcount = _N
        
        forvalues num = 1/`varcount' {
         local varwithoutvallab`num' = name[`num']
         local vallabname`num' = vallab[`num']
        }
        
        restore
        
        forvalues num = 1/`varcount' {
         if ("`vallabname`num''" != "`varwithoutvallab`num''" & "`vallabname`num''" != "") {
          la copy `vallabname`num'' `varwithoutvallab`num'', replace
         }
        }
        
        foreach var of varlist _all {
         cap la value `var' `var'
        }
        
        end
        Thanks

        Comment


        • #5
          I don't see any problem with the code in #4. I tried it on a data set I recently received from somebody that has value labels named label1, label2, label3, etc. and it worked very nicely.

          Comment


          • #6
            Happy that I'm learning from very useful posts on Statalist. Thanks for your time.

            Comment


            • #7
              When I wrote #2, I was thinking that the problem could be solved with one line

              Code:
              elabel rename * , lower
              And, depending on the details, that one line could indeed work just fine.

              More generally speaking, using variable names as value label names is usually not necessary; yet people often want that. There is a command on SSC, valtovar, that does this. The command has the same potential problem as the program suggested in #4 has. Here is a situation in which the suggested approach fails badly:

              Code:
              clear
              input foo bar
              42 73
              73 42
              end
              
              label define xxx 42 foo 73 bar
              label define foo 42 BAR 73 FOO
              
              label values foo xxx
              label values bar foo
              
              list
              label list
              
              labelfix
              
              list
              label list
              I say the approach fails badly because on the surface everything looks fine even though we have completely messed up our value labels. You could work around that problem by first creating temporary value labels and then rename those in a second run through the loop -- I will not go there. Another thing to think about is multilingual datasets but I will not go there, either.

              Aside from the serious problem that I have shown above, the code in #4 should work but is not as efficient as it could be. As a safe(er) and more efficient code, I suggest

              Code:
              foreach var of varlist * {
                  local lbl : value label `var'
                  if ( mi("`lbl'") ) continue
                  label copy `lbl' `var'
                  label values `var' `var'
              }
              The code will fail (on purpose) for any value label that is already defined. To prevent you from ending with a dataset where half the labels have been changed until an error occurs, you could

              Code:
              preserve
              foreach var of varlist * {
                  local lbl : value label `var'
                  if ( mi("`lbl'") ) continue
                  label copy `lbl' `var'
                  label values `var' `var'
              }
              restore , not
              In case of an error, Stata will then return to the state for the original dataset before the loop.


              Edit: One more note on the code suggested in #4.

              Code:
              cap la value `var' `var'
              will attach value labels to every numeric variable in the dataset, regardless of whether such value labels exist (i.e., are defined in memory) or not. That is probably not what you want.


              One last Edit; modifying Clydes code using elabel

              Code:
              ds , has(vallabel)
              foreach var in `r(varlist)' {
                  elabel copy (`var') `var':`var'
              }
              Last edited by daniel klein; 20 Sep 2020, 04:29.

              Comment


              • #8
                Thank you Dan for finding this bug and saving me from big trouble which would be even difficult to detect.
                The problem with code #4 is serious and I just could not imagine it. This problem is addressed by your following code (it gives error and the label values are saved from getting messed up)
                Code:
                preserve
                foreach var of varlist * {
                    local lbl : value label `var'
                    if ( mi("`lbl'")) continue
                    label copy `lbl' `var'
                    label values `var' `var'
                }
                restore , not
                I did a small modification to this for addressing "The code will fail (on purpose) for any value label that is already defined" issue
                Code:
                preserve
                foreach var of varlist * {
                    local lbl : value label `var'
                    if ( mi("`lbl'") | "`lbl'" == "`var'" ) continue
                    label copy `lbl' `var'
                    label values `var' `var'
                }
                restore , not
                Thanks a lot!

                Comment

                Working...
                X