0
votes

I am touching up some SAS code I wrote and found a chunk of code I wish to execute more effectively. I have a time-series data set called 'Forecasts' which just consists of date and the 'Forecast' variable for a given date.

I wrote a simple block of code to take this variable and basically chop it up into a series of variables, each one representing one date:

data forecasts;
set forecasts;
  obs=_n_; 
  array r(241);
  do i=1 to dim(r);
    if obs=i then r(i)=Forecast;
  end; drop i; drop obs; drop forecast;
run;

However, the 'r(241)' part of this code really annoys me. I already have a macro variable which corresponds to the number of times I need to perform this operation (called 'n'), and I would rather just plug it into the array proclamation directly, something like:

array r(&n)

etc.

However macro variables are obviously considered text, so even when I managed to import the macro variable into the data step, variants r(&n) doesn't work because it doesn't read 'n' as a numeric. Outside of wrapping this entire data step into a broader macro, how can I pull 'n' into the data step then convert it to a numeric so this operation works?

2

2 Answers

2
votes

The statement:

array r(&n) ;

should be fine, assuming the macro variable is defined and has an integer value. Please show how you are trying to use it (and any failing log messages). You don't need to 'import macro variables into the data step'. Macro variables are text because their primary job is to resolve to SAS code.

18   %let n=3;
19   data _null_;
20     array r{&n};
21     do i=1 to dim(r);
22       put i=;
23     end;
24   run;

i=1
i=2
i=3
2
votes

Just as a suggestion, you don't need to do it this way. PROC TRANSPOSE exists for this purpose. Then you don't even have to know how many variables/rows there are.

data forecast;
  call streaminit(7);
  do id = 1 to 243;
    forecast = rand('Normal')*5;
    output;
  end;
run;

proc transpose data=forecast out=forecasts prefix=r;
  by id;
  id id;
  var forecast;
run;

If you don't actually want 243 rows but want just one, dump the by and the id statements.

Even if you wanted to do it in a data step, you could do this quite a bit faster (Right now you're checking 241 * 241 times, you only need 241 times...) by putting the set inside the loop. Here I use the automatically dropped variable _n_ to iterate the loop.

data forecasts;
  do _n_ = 1 by 1 until (eof);
    set forecast end=eof;
    array r(243);
    r[_n_] = forecast;
    output; *if you actually want one row per original row still;
    call missing(r[_n_]); *clear it out;
  end;
  drop forecast;
run;