Are there any functions in Base SAS (I do not have SAS enterprise miner) to compute the convolution of two vectors???
Please guide. Thank you.
The other responders are more versed than I am regarding the suitability and efficiency of the math involved. However, that said, one minor correction you could make to your code in order to attain the results you want is:
data test;
input X Y A Z;
cards;
1 10 0.1 0
2 20 0.2 0
3 30 0.3 0
4 40 0.4 0
5 50 0.5 0
;
run;
data _null_;
if 0 then set test nobs=nobs;
CALL SYMPUT('NUMREC',nobs); /*** put # of records into NUMREC macro var ***/
stop; /*** stop, got number of records ***/
run;
/* now read values of x and y into arrays, and then
reread test and do calculations*/
data want (drop=_:);
array _xval(&numrec); /* create three arrays with same
number of elements as there are
records in test
*/
array _yval(&numrec);
array _Aval(&numrec);
_i=0;
do until (eof1); /* load the array with a, x and y values */
set test end=eof1;
_i+1;
_xval(_i)=x;
_yval(_i)=y;
_aval(_i)=a;
end;
_rec=-1;
do until (eof2); /* read in each record separately */
set test end=eof2;
_rec+1;
z=0;
do _i=1 to _rec;
z+_xval(_i)*_yval(&numrec-_rec+_i);
end;
if _rec gt 0 then _xval(_rec+1)=sum(_aval(_rec+1),z);
output;
end;
run;
I don't think there is in base sas, but there is if you license IML (e.g., http://support.sas.com/documentation/cdl/en/imlug/59656/HTML/default/viewer.htm#langref_sect138.htm ).
Thanks art297. I do not have IML. Looking for a way to implement it in Base SAS itself.
Is there a way to implement the vector operations shown below in Base SAS??
In the example below, data table test1 contains three variable Variable1, Variable2 and Variable3.
DATA test1;
set test1;
DO i = 1 to num;
set test1 nobs point = i;
variable1= sum(variable2[1:i-1]*variable3[(num-i+2)]:num)];
END;
RUN;
Thank you.
Of course there is, but you would have to show a small example with some data and what should go into the calculations. e.g., when i eq 1 what value should the calculation sum(variable2[1:i-1] get?
What is the maximum number of records you will have? If it isn't too big, an easy solution might be to just preload the entire table into an array.
Hi art297, my dataset has close to 10,000 observations. The following is a sample dataset:
DATA test;
input X Y Z;
cards;
1 10 0
2 20 0
3 30 0
4 40 0
5 50 0
;
run;
I have also given some sample calculations below:
Iteration 1:
SUM(X[1:1]*Y[5–2+2:5]) = SUM(X[1:1]*Y[5:5]) = SUM([1]*[50]) = 50
Iteration 2:
SUM(X[1:2]*Y[5–3+2:5]) = SUM(X[1:2]*Y[4:5]) = SUM([1,2]*[40,50]) = SUM(40+100) = 140
Iteration 3:
SUM(X[1:3]*Y[5–4+2:5]) = SUM(X[1:3]*Y[3:5]) = SUM([1,2,3]*[30,40,50]) = SUM(30+80+150) = 260
… so on
The final dataset after all the calculations will look like this
DATA test;
input X Y Z;
cards;
1 10 0
2 20 50
3 30 140
4 40 260
5 50 400
;
run;
Thank you.
In my previous post, Z corresponds to Variable 1, X corresponds to Variable 2 and Y corresponds to Variable 3.
Thanks.
This may not be the fastest way, but it should work for any size vectors.
DATA test;
input X Y expZ;
cards;
1 10 0
2 20 50
3 30 140
4 40 260
5 50 400
;
run;
data want ;
set test nobs=nobs ;
z=0;
i=_n_-1;
do p1=1 to i;
p2=nobs -i + p1 ;
set test (keep=x rename=(x=x1)) point=p1;
set test (keep=y rename=(y=y1)) point=p2;
z1=(x1*y1);
z=sum(z,z1);
* put (_n_ i p1 p2 x1 y1 z1 z) (=);
end;
run;
proc print width=min;
run;
Obs X Y expZ z i x1 y1 z1
1 1 10 0 0 0 . . .
2 2 20 50 50 1 1 50 50
3 3 30 140 140 2 2 50 100
4 4 40 260 260 3 3 50 150
5 5 50 400 400 4 4 50 200
The following doesn't look as tidy as Tom's suggested code but, with 10000 records, took 6 seconds on my machine, while Tom's approach took over a minute:
/*create some test data*/
DATA test (drop=i);
input X Y Z;
do i=1 to 2000;
output;
end;
cards;
1 10 0
2 20 0
3 30 0
4 40 0
5 50 0
;
data _null_;
if 0 then set test nobs=nobs;
CALL SYMPUT('NUMREC',nobs); /*** put # of records into NUMREC macro var ***/
stop; /*** stop, got number of records ***/
run;
/* now read values of x and y into arrays, and then
reread test and do calculations*/
data want (drop=_:);
array _xval(&numrec); /* create two arrays with same number of
elements as there are records in test
*/
array _yval(&numrec);
i=0;
do until (eof1); /* load the array with x and y values */
set test end=eof1;
i+1;
_xval(i)=x;
_yval(i)=y;
end;
_rec=-1;
do until (eof2); /* read in each record separately */
set test end=eof2;
_rec+1;
z=0;
do _i=1 to _rec;
z+_xval(_i)*_yval(&numrec-_rec+_i);
end;
output;
end;
run;
Thanks a lot Tom and Art. I am looking at Art's solution since it is faster (For a record with 8000+ records it takes around 1.9 secs). Speed is very critical since this is going to be called multiple times for optimization. Any faster solution is welcome.
I am trying out one more enhancement to the code with an additional variable A as follows (A is just another variable in the dataset):
DO i = 1 to num;
set test nobs point = i;
Z = sum(X[1:i-1]*Y[(num-i+2)]:num)];
X = A + Z;
END;
RUN;
I tried the following but it isn't giving the expected solution:
data _null_;
if 0 then set test nobs=nobs;
CALL SYMPUT('NUMREC',nobs); /*** put # of records into NUMREC macro var ***/
stop; /*** stop, got number of records ***/
run;
/* now read values of x and y into arrays, and then
reread test and do calculations*/
data want (drop=_:);
array _xval(&numrec); /* create two arrays with same number of
elements as there are records in test
*/
array _yval(&numrec);
array _Aval(&numrec);
i=0;
do until (eof1); /* load the array with x and y values */
set test end=eof1;
i+1;
_xval(i)=x;
_yval(i)=y;
_Aval(i) = A;
end;
_rec=-1;
do until (eof2); /* read in each record separately */
set test end=eof2;
_rec+1;
z=0;
do _i=1 to _rec;
z+_xval(_i)*_yval(&numrec-_rec+_i);
_xval(_i) = _Aval(_i) + z;
end;
output;
end;
run;
Can someone please point out the correct approach???
Thank you
I haven't looked at all of your code, but noticed that you never declared the new array. Make sure that you add one. e.g.
array _xval(&numrec); /* create THREE arrays with same number of
elements as there are records in test
*/
array _yval(&numrec);
array _Aval(&numrec);
Art,
That was a typo in the code I pasted here. In the actual code have declared it. It still doesn't work.
Thank you.
Was this also just a typo?:
-xval(_i) = _Aval(_i) + z;
Or should it have been _xval(_i) = _Aval(_i) + z;
And, of course, that will use the new values in all of the later calculations. Is that what you want?
Oops...sorry. That was another typo.
New values are to be used in the later calculation. But only the current i is replace in each iteration.
Thank you.
Then, I suggest that you post an expansion of your original sample data, including the new variable, and what you want as an output.
Art,
Please find below the new data and the expected output.
DATA test;
input X Y A Z;
cards;
1 10 0.1 0
2 20 0.2 0
3 30 0.3 0
4 40 0.4 0
5 50 0.5 0
;
run;
DATA results;
input X Y A Z;
cards;
1.0 10 0.1 0
50.2 20 0.2 50
2550.3 30 0.3 2550
129553.4 40 0.4 129553
6581208.5 50 0.5 6581208
;
run;
Thank you
Build your skills. Make connections. Enjoy creative freedom. Maybe change the world. Registration is now open through August 30th. Visit the SAS Hackathon homepage.
Register today!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.
Select SAS Training centers are offering in-person courses. View upcoming courses for: