Announcement

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

  • Is there a command or an easy way to recode and define new value label

    Dear Stata users,

    As we know, when we recode a variable, we can define a new value label simultaneously. My question is about how to define value label more easily. Suppose we want to define a value label just corresponding to the recode rule, then we must write the same rule text in double quotes ( "" ). If there are a lot of recode rules, this work will be tedious. So, is there any way to get rid of that? That is to say, remove texts in double quotes ("1/10", for example) in the following codes, but attain the same outcomes.

    Code:
    recode varname (0=0 "0") (1/10=1 "1/10") (11/20=2 "11/20") (21/30=3 "21/30") (31/40=4 "31/40") (41/50=5 "41/50") (51/60=6 "51/60") (61/70=7 "61/70") (71/110=8 "71/110"), gen(newvar)
    Last edited by Chen Samulsion; 28 Oct 2021, 09:28.

  • #2
    I don't know if you consider this simpler or not, but it's how I would probably handle this situation:

    Code:
    clear*
    set obs 250
    gen varname = runiformint(0, 110)
    
    
    replace varname = ceil(varname/10)
    replace varname = 8 if varname > 8
    forvalues i = 1/7 {
        label define newlabel `i' "`=10*`i'-9' - `=10*`i''", add
    }
    label define newlabel 8 "71 - 110", add
    label define newlabel 0 "0", add
    label values varname newlabel
    
    tab varname

    Comment


    • #3
      Here is the outline for a more general approach

      Code:
      local rules (0 = 0) (1/10 = 1) (11/20 = 2)
      
      while ("`rules'" != "") {
          gettoken rule rules : rules , match(lpar)
          gettoken lhs rule : rule , parse("=")
          gettoken eqs rule : rule , parse("=")
          gettoken rhs rule : rule
          
          label define mylbl `rhs' "`lhs'" , add 
      }
      
      label list mylbl

      Comment


      • #4
        Thank you very much Clyde Schechter daniel klein.
        Invention, in my opinion, arises directly from idleness, possibly also from laziness —— Agatha Christie

        Comment


        • #5
          I may add that I cannot think of many situations in which you would want to do (exactly) this. And, even in these situations, I can easily think of various alternative labels that might or might not be preferred, such as "1-10", "1 to 10", or "1 <= x <= 10". In my view, these foreseeable required ad-hoc adjustments undermine the attempts to develop a general solution.

          Comment


          • #6
            Yes, I do not desire to copy exactly the same texts as recode rules. I just want to inquires into the possibility. If it is possible to attain what I want in 1#, then I can modify the resulting value labels using some related commands.

            Comment


            • #7
              Using daniel klein's codes in #3, I achieved what I'd hoped to do.

              Code:
              *!Written in 2021.10.30 by Chen Samulsion
              *!Use pieces of codes from official -recode- and Daniel Klein
              
              program define recode2
              
              syntax anything(equalok name=vrules id="varlist (rule)..") [, VARlist(varlist)]
              
              //syntax 1: tok1 is varlist, tmp is a list of parenthesized rules
                gettoken tok1 tmp : vrules , parse("(")
                gettoken tok2 : tmp, parse("(")
              
                if trim(`"`tok2'"') == "(" {
                  unab vlist : `tok1'
                  local nvlist : word count `vlist'
                  local rules `"`tmp'"'
                  local parens = 1
                }
              
                while ("`rules'" != "") {
                  gettoken rule rules : rules , match(lpar)
                  gettoken lhs rule : rule , parse("=")
                  gettoken eqs rule : rule , parse("=")
                  gettoken rhs rule : rule    
                  label define `tok1' `rhs' "`lhs'", add modify
                }
              
                if "`varlist'"!="" {
                  label values `varlist' `tok1'
                }
                else label values `tok1' `tok1'
              
                uselab `tok1' //List value labels and variables using them. Note: uselab (SSC)
                label list `tok1'
              
              end
              Code:
              sysuse lifeexp, clear
              recode lexp (54/60=1) (61/65=2) (66/70=3) (71/79=4)
              recode2 lexp (54/60=1) (61/65=2) (66/70=3) (71/79=4)
              recode lexp (54/60=1) (61/65=2) (66/70=3) (71/79=4), gen(lexp2)
              recode2 lexp (Age 54~60=1) (Age 61~65=2) (Age 66~70=3) (Age 71~79=4), var(lexp2)
              tab1 lexp lexp2

              Comment


              • #8
                I am glad to hear that you are satisfied with your solution.

                However, I notice that the modfided recode code does not actually recode variables. This is evident in your last example:

                Code:
                recode lexp (54/60=1) (61/65=2) (66/70=3) (71/79=4), gen(lexp2)
                recode2 lexp (Age 54~60=1) (Age 61~65=2) (Age 66~70=3) (Age 71~79=4), var(lexp2)
                Here, you call recode and then recode2. That is, you still have to specify the rules twice, which I thought was what you wanted not to avoid in the first place. I do not see how these two lines of code are more convenient (or readable) than

                Code:
                recode lexp (54/60 =  1 "Age 54~60") ... (71/79 = 4 "Age 71~79") , generate(lexp2)

                I also notice that you use uselab, part of labutil2 (SSC). If you are interested in tools for managing value labels, you might want to check out elabel from SSC. The commands were first introduced here and then more formally presented in Klein, 2019.

                Edit:

                For example, to go from

                Code:
                . label list lexp
                lexp:
                           1 54/60
                           2 61/65
                           3 66/70
                           4 71/79
                to

                Code:
                . label list
                lexp:
                           1 Age 54~60
                           2 Age 61~65
                           3 Age 66~70
                           4 Age 71~79
                you type

                Code:
                elabel define lexp (= #) (= "Age " + subinstr(@, "/", "~", 1)) , modify

                Klein, D. 2019. Extensions to the label commands. The Stata Journal, 19(4), 867--882.
                Last edited by daniel klein; 30 Oct 2021, 14:42.

                Comment


                • #9
                  daniel klein you are quite right in pointing out what I want in the first place and what I actually get by now. In the outset, I intended to recode and generate value labels simultaneously by the anticipated recode2. However, I can not achieve that, so I choose the way as it is now, that is to say I should specify the rules twice (recode to do recode, and recode2 to generate value labels). From the perspective of personal habits of using Stata, the combination of recode and recode2 is more convenient for me than typing value label texts in double quotes, sometimes I hate double quotes. And thank you for your recommending elabel package suits. I encounter it very often, and since I have installed labutil and labutil2 and so many other commands for data management, I decided not to install it.
                  Last edited by Chen Samulsion; 30 Oct 2021, 19:03.

                  Comment

                  Working...
                  X