BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
vioravis
Calcite | Level 5

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.

1 ACCEPTED SOLUTION

Accepted Solutions
art297
Opal | Level 21

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;

View solution in original post

26 REPLIES 26
art297
Opal | Level 21

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 ).

vioravis
Calcite | Level 5

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.

art297
Opal | Level 21

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.

vioravis
Calcite | Level 5

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.

vioravis
Calcite | Level 5

In my previous post, Z corresponds to Variable 1, X corresponds to Variable 2 and Y corresponds to Variable 3.

Thanks.

Tom
Super User Tom
Super User

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

art297
Opal | Level 21

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;

vioravis
Calcite | Level 5

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

art297
Opal | Level 21

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);

vioravis
Calcite | Level 5

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.

art297
Opal | Level 21

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?

vioravis
Calcite | Level 5

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.

art297
Opal | Level 21

Then, I suggest that you post an expansion of your original sample data, including the new variable, and what you want as an output.

vioravis
Calcite | Level 5

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

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 26 replies
  • 3368 views
  • 6 likes
  • 6 in conversation