1

The question is simple, hope the answer too.

Is there a way (call execute, macro, symput, etc etc) to rewrite the following code in order to make it more powerfull, using SAS in a good way?

data get;
    set have; 
    by pid year;
    if first.year then do;
        if      year = 2017 then f2017 = 1;
        else if year = 2018 then f2018 = 1;
        else if year = 2019 then f2019 = 1;
    end;
run;

This is a try, but it doen't work:

data _null_;
    set have end=last; 
    if _n_ = 1 then call execute('data get;set have;by pid year; ');
    call execute(cats('if first.year then f',year,'=1;'));
    if last then call execute('run;');

run;
1
  • 1
    Why do you have the BY statement and the FIRST.YEAR? Please show some example input and output dataset to show what transformation you are actually trying to do. Are you sure you don't want to use PROC TRANSPOSE? Commented Sep 21, 2021 at 12:20

2 Answers 2

3

Variation on the array solution above by using specific indexes.

data want;
    set have;
    array f[2017:2020] f2017-f2020;


    f(year) = 1;

run;
Sign up to request clarification or add additional context in comments.

Comments

2

If your variables are all sequentially ordered, use an array to create your variables automatically using the shortcut:

var<min> - var<max>

For example, var1-var4 is automatically interpreted as var1 var2 var3 var4.

Use the new variable's actual name to compare against the year. The below code creates a binary 1/0 variable prefixed with f for each year.

Simple Answer

data want;
    set have;
    array f[*] f2017-f2020;

    /* Grab the year part of the variable name and compare it to the year. */
    do i = 1 to dim(f);
        f[i] = ( input(substr(vname(f[i]), 2), 4.) = year );
    end;

    drop i;
run;

Output:

year    f2017   f2018   f2019   f2020
2017    1       0       0       0
2018    0       1       0       0
2019    0       0       1       0
2020    0       0       0       1

More Dynamic Version

If you need this to be a little more dynamic, you can read in the min/max year from a macro variable. For example:

proc sql noprint;
    select min(year)
         , max(year)
    into :min_year
       , :max_year
    from have
    ;
quit;

data want;
   set have;
   array f[*] f&min_year. - f&max_year.;
   ...

Even More Dynamic Version

And if you really needed to get dynamic, you can read in every single value into a space-separated macro variable list. A single macro variable will max out at 65,534 characters, so you have plenty of room to add variables.

proc sql noprint;
    select distinct cats('f', year)
    into :values separated by ' '
    from have
    ;
quit;

data want;
   set have;
   array f[*] &values.;
   ...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.