Announcement

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

  • return the elements with absolute values

    Dear All, Suppose that I have
    Code:
    * Example generated by -dataex-. For more info, type help dataex
    clear
    input float(id v1 v2 v3 x)
    1 -1  3 -2 -1
    2  2  1 -3  1
    3  3 -2  4  2
    end
    For each row, the desired variable x is the element among v1, v2 and v3 with the smallest "absolute" value. Any suggestions? Thanks.
    Ho-Chuan (River) Huang
    Stata 17.0, MP(4)

  • #2
    Maybe something like this?
    Code:
    version 17.0
    
    clear *
    
    quietly input int(id v1 v2 v3 x)
    1 -1  3 -2 -1
    2  2  1 -3  1
    3  3 -2  4  2
    end
    
    frame copy default shadows
    frame shadows {
        drop x
        reshape long v, i(id) j(idx)
        generate int v2 = v * v
        bysort id (v2): keep if _n == 1 // assumes no -1 and 1 within ID
    }
    
    frlink 1:1 id, frame(shadows)
    frget v, from(shadows)
    
    frame drop shadows
    drop shadows
    
    list, noobs
    
    assert v == x // You have an error in your third observation.
    
    exit
    There are likely more elegant ways that don't involve -reshaping, and you could also use Mata, but -frames- might be more convenient.

    Comment


    • #3
      Based on your description, I believe you want something like:
      Code:
      reshape long v, i(id)
      gen wanted = abs(v)
      by id (wanted), sort: replace wanted = v[1]
      reshape wide
      However, for id 3, the v with smallest absolute value is v2 = -2, yet you show x = +2. I can't make sense of that.

      There is another issue. Suppose we had v1 = 1, v2 = -1, v3 = 5. Then v1 and v2 both have the smallest absolute value, namely 1. But it is unclear whether x should be 1 or -1, and how that would be decided. (The code above would break the tie at random and irreproducibly.)

      Added: Crossed with #2. Yes, this can be done without reshaping, by cloning all the v* variables and taking absolute values, -rowsort-ing the clones, and doing some dancing around the v's to then match the value of the lowest absolute value. But I think the code would be an opaque mess, and I think it would scale badly if the actual number of v variables is large.
      Last edited by Clyde Schechter; 21 Apr 2022, 23:19.

      Comment


      • #4
        Clyde, I agree that that would be a can of worms, but I was thinking something more along the lines of
        Code:
        quietly generate int min_v = .
        foreach var of varlist v? {
            quietly replace min_v = `var' if abs(`var') < abs(min_v)
        }
        .ÿ
        .ÿversionÿ17.0

        .ÿ
        .ÿclearÿ*

        .ÿ
        .ÿquietlyÿinputÿint(idÿv1ÿv2ÿv3ÿx)

        .ÿ
        .ÿ*
        .ÿ*ÿBeginÿhere
        .ÿ*
        .ÿquietlyÿgenerateÿintÿmin_vÿ=ÿ.

        .ÿforeachÿvarÿofÿvarlistÿv?ÿ{
        ÿÿ2.ÿÿÿÿÿÿÿÿÿquietlyÿreplaceÿmin_vÿ=ÿ`var'ÿifÿabs(`var')ÿ<ÿabs(min_v)
        ÿÿ3.ÿ}

        .ÿ
        .ÿlist,ÿnoobs

        ÿÿ+--------------------------------+
        ÿÿ|ÿidÿÿÿv1ÿÿÿv2ÿÿÿv3ÿÿÿÿxÿÿÿmin_vÿ|
        ÿÿ|--------------------------------|
        ÿÿ|ÿÿ1ÿÿÿ-1ÿÿÿÿ3ÿÿÿ-2ÿÿÿ-1ÿÿÿÿÿÿ-1ÿ|
        ÿÿ|ÿÿ2ÿÿÿÿ2ÿÿÿÿ1ÿÿÿ-3ÿÿÿÿ1ÿÿÿÿÿÿÿ1ÿ|
        ÿÿ|ÿÿ3ÿÿÿÿ3ÿÿÿ-2ÿÿÿÿ4ÿÿÿÿ2ÿÿÿÿÿÿ-2ÿ|
        ÿÿ+--------------------------------+

        .ÿ
        .ÿexit

        endÿofÿdo-file


        .

        Comment


        • #5
          Dear Clyde, Thanks for the suggestion. My bad, it should be x=-2 for id 3.
          Ho-Chuan (River) Huang
          Stata 17.0, MP(4)

          Comment


          • #6
            Dear Joseph, Thanks for the suggestion.
            Ho-Chuan (River) Huang
            Stata 17.0, MP(4)

            Comment

            Working...
            X