Dear SAS experts
I have some code which I cannot get to work. I want to use the data points for each numeric variable in the first observation and divide by this number in the data points below the first observation. I can get it to work if I take one variable at a time, but I cannot get the code with an array to work. Specifically, I cannot seem to define the variable which is retained and used in the simple calculation (see ?????). Does anyone have a suggestion on how get the code to work using an array? Thank you.
data have;
input varone vartwo varthree varfour;
datalines;
1 2 1.5 5
1 2 1 1
1 3 1 2
1 4 3 10
;
run;
data have;
set have;
globalcatvar="1";
run;
*No array;
data want_three;
set have;
by globalcatvar;
retain firstvartwo;
if first.globalcatvar then firstvartwo=vartwo;
if _n_>1 then vartwo=vartwo/firstvartwo;
run;
*With array;
data want_three;
set have;
array modify {*} _NUMERIC_;
do i=1 to dim(modify);
by globalcatvar;
retain ?????;
if first.globalcatvar then ?????=modify{i};
if _n_>1 then modify{i}=modify{i}/?????;
end;
run;
I think the right approach is to use a _TEMPORARY_ array, these are automatically retained:
data want_three;
set have;
by globalcatvar;
array modify {*} _NUMERIC_;
array retains (200) 8 _temporary_;
if first.globalcatvar then do i=1 to dim(modify);
retains(i)=modify(i);
end;
else do i=1 to dim(modify);
modify{i}=modify{i}/retains(i);
end;
run;
Please show the expected result.
You may need to arrays, one for the values in the current observation, another one for the retained variables, both need variable-names, _numeric_ won't work.
Hey Andreas
Thanks.
For vartwo, I would like it to make the following change:
2 = 2 (no change)
2 = 2/2 = 1
3 = 3/2 = 1.5
4 = 4/2 = 2
Specifically, each number is divided by the first data point.
So some code which looks something like this (although the array does not work)?
data have;
input varone vartwo varthree varfour;
datalines;
1 2 1.5 5
1 2 1 1
1 3 1 2
1 4 3 10
;
run;
data have;
set have;
globalcatvar="1";
run;
*Array:
data want_three;
set have;
array modify {4} varone vartwo varthree varfour;
array modify_r {4} varone_r vartwo_r varthree_r varfour_r;
do i=1 to 4;
by globalcatvar;
retain modify_r{i};
if first.globalcatvar then modify_r{i}=modify{i};
if _n_>1 then modify{i}=modify{i}/modify_r{i};
end;
run;
Still not clear, why globalcatvar is defined ... the following step is build on some assumptions:
- you want to divide varthree and varfour also
- varone is constant
data want;
set have;
array vars[3] vartwo varthree varfour;
array re[3] _temporary_;
if _n_ = 1 then do;
do i = 1 to dim(re);
re[i] = vars[i];
end;
end;
else do;
do i = 1 to dim(re);
vars[i] = vars[i] / re[i];
end;
end;
drop i;
run;
Hey Andreas
Thanks. No, I might not need globalcatvar.
Your code looks interesting. Is it possible to modify it such that all numeric variables are included in vars (and that the rest of the code can be modified to work too)?
Thanks
untested:
proc sql noprint;
select num_numeric into :numVars trimmed
from sashelp.vtable
where libname = 'WORK' and memname = 'HAVE'
;
quit;
data want;
set have;
array vars _numeric_;
array re[&numVars.] _temporary_;
if _n_ = 1 then do;
do i = 1 to dim(re);
re[i] = vars[i];
end;
end;
else do;
do i = 1 to dim(re);
vars[i] = vars[i] / re[i];
end;
end;
drop i;
run;
I think the right approach is to use a _TEMPORARY_ array, these are automatically retained:
data want_three;
set have;
by globalcatvar;
array modify {*} _NUMERIC_;
array retains (200) 8 _temporary_;
if first.globalcatvar then do i=1 to dim(modify);
retains(i)=modify(i);
end;
else do i=1 to dim(modify);
modify{i}=modify{i}/retains(i);
end;
run;
Hey s_lassen
The code looks very cool. Thanks.
But what is the signifiance of (200) and 8 specified in the array 'retains'? Is 200 just a large number (could e.g. also have been 400) ?
Thanks
200 is just a number that I assume is larger than the dimension of of the other array, but not so large that it takes up all available memory. There is probably no problem in increasing it to e.g. 2000 if you sometimes have that many numeric variables.
8 is just the length of the array elements, as there is no dollar sign, it defines the _TEMPORARY_ array as numeric.
By "dimension" do you mean number of elements in the array?
So the "8" says something about how large the numbers included in the array retains are expected to be?
I am relatively new to SAS coding.
I slightly changed some of your code. I removed the the by-code and the globalcatvar, which I thought was neccessary. The code seems to be doing what I was hoping for. Moreover, it does appear that the code below would work without any knowledge about the number of numeric variables in the dataset?
data have;
input varone vartwo varthree varfour;
datalines;
1.1 2 1.5 5
1 2 1 1
1 3 1 2
1 4 3 10
;
run;
data want_three;
set have;
array modify {*} _NUMERIC_;
array retains (200) 8 _temporary_;
if _n_=1 then do i=1 to dim(modify);
retains(i)=modify(i);
end;
else do i=1 to dim(modify);
modify{i}=modify{i}/retains(i);
end;
run;
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 25. Read more here about why you should contribute and what is in it for you!
Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.