0
votes
data output;
set input;
by id;
if first.id = 1 then do; 
    call symputx('i', 1); ------ also tried %let i = 1;
    a_&i = a;
end;
else do;
    call symputx('i', &i + 1);  ------ also tried %let i = %sysevalf (&i + 1);
    a_&i = a;
end;
run;

Example Data:

ID    A
1     2
1     3
2     2
2     4

Want output:

ID    A    A_1    A_2
1     2     2      .
1     3     .      3
2     2     2      .
2     4     .      4

I know that you can do this using transpose, but i'm just curious why does this way not work. The macro does not retain its value for the next observation.

Thanks!

edit: Since %let is compile time, and call symput is execution time, %let will run only once and call symput will always be 1 step slow.

1
if you set macro variable, you can't use it in same datastepSanek Zhitnik
ahhh, i see. Then how will you go about doing this without transpose?Senneth

1 Answers

1
votes

why does this way not work

The sequence of behavior in SAS executor is

  • resolve macro expressions
  • process steps
    • automatic compile of proc or data step (compile-time)
    • run the compilation (run-time)
    • a running data step can not modify its pdv layout (part of the compilation process) while it is running.

call symput() is performed at run-time, so any changes it makes will not and can not be applied to the source code as a_&i = a;

Array based transposition

You will need to determine the maximum number of items in the groups prior to coding the data step. Use array addressing to place the a value in the desired array slot:

* Hand coded transpose requires a scan over the data first;

* determine largest group size;
data _null_;
  set have end=lastrecord_flag;
  by id;
  if first.id 
    then seq=1;
    else seq+1;
  retain maxseq 0;
  if last.id then maxseq = max(seq,maxseq);
  if lastrecord_flag then call symputx('maxseq', maxseq);
run;

* Use maxseq macro variable computed during scan to define array size;
data want (drop=seq);
  set have;
  by id;
  array a_[&maxseq];  %* <--- set array size to max group size;
  if first.id 
    then seq=1;
    else seq+1;

  a_[seq] = a; * 'triangular' transpose;
run;

Note: Your 'want' is a triangular reshaping of the data. To achieve a row per id reshaping the a_ elements would have to be cleared (call missing()) at first.id and output at last.id.