## DATA Step, Macro, Functions and more

Frequent Contributor
Posts: 91

Good morning folks!

I'm stumped and need your help.

Basic premise - we are playing with various scenarios in our data, and one
of them is to adjust datasets based on critical values.

The logic flow is to take the original dataset (which is divided into
segment groupings), generate the statistic of interest by segment, and
compare it to the chosen critical values for that segment.

If the calculated statistic is smaller than the critical value for a
segment, send the data out to a 'completed' dataset (ITSDONE).

If the calculated statistic is larger than the critical value for a
segment, delete the largest value in the dataset, and repeat until the critical value test is
satisfied (NOTDONE).

Unfortunately, I can't seem to figure out how to stop the do loop when
the critical value test is satisfied (when NOTDONE is empty).

The particular combination we are looking at right now requires 751
iterations for all segments to meet the test criteria.

...until we change something (which we immediately will).

I need to be able to do this without 'knowing' anything but the critical value and statistic.

Thanks so much for your help!

Wendy T.

Dataset START already contains the critical value (K_CRIT), and is sorted
by descending values of the variable ANGLE_K by SEGMENT.

one line with null values.

DATA LOOP ; SET START ;
PROC MEANS NOPRINT N DATA=LOOP ;
BY SEGMENT ;
VAR ANGLE_K ;
OUTPUT OUT=ORIG1 (DROP= _TYPE_ _FREQ_) N=ORIGINAL_N ; RUN ;
RUN ;

%MACRO CUTTOPVALUE ;

%DO I=1 %TO 751 ;

PROC MEANS NOPRINT DATA=LOOP ;
BY SEGMENT ;
VAR ANGLE_K ;
OUTPUT OUT=MEDIANS (DROP=_TYPE_) MEDIAN=MEDIAN ;
RUN ;

PROC SQL NOPRINT ;
CREATE TABLE CHECKER
AS SELECT LOOP.*, MEDIANS.MEDIAN, MEDIANS._FREQ_
FROM LOOP, MEDIANS
WHERE LOOP.SEGMENT=MEDIANS.SEGMENT ;
QUIT ;

DATA ITSDONE NOTDONE (DROP=MEDIAN _FREQ_) ; SET CHECKER ;
IF MEDIAN LE K_CRIT THEN OUTPUT ITSDONE ;
ELSE OUTPUT NOTDONE ;
RUN ;

DATA STACKER ; SET ITSDONE STACKER ;
IF SEGMENT = '' THEN DELETE ;
PROC SORT ; BY SEGMENT ; RUN ;

DATA LOOP ; SET NOTDONE ;
IF _N_ = 1 THEN DELETE ;
RUN ;

%END ;

%MEND CUTTOPVALUE ;

%CUTTOPVALUE ;

DATA FINISHED ; MERGE STACKER ORIG1 ; BY SEGMENT ; RUN ;
Super User
Posts: 5,884

I'm guessing that in you last data step within the macro loop know if you need to iterate again or not.
If your don't need any more iterations, just call symput to a macro variable a certain value. This together with a %DO %WHILE or %UNTIL logic perhaps can do what you want?

/Linus
Data never sleeps
Frequent Contributor
Posts: 91

I finally figured it out!

Sorry to not explain well. Yes, my object was to get the number of observations remaining in dataset LOOP to see if I needed to iterate again.

I was trying to use %symput to get the number of observations, but for some reason, I could not get it to work. (an example using call symput would be very welcome - I just now took a look at the documentation, and it's very unclear to me how to use it).

So I went another way and matched the DO UNTIL with PROC SQL to the dictionary table.

Wendy T.

%MACROCUTTOPVALUE ;

%DO %UNTIL (&NUMBOBS = 0) ;

...as before ...

PROC SQL NOPRINT ;
SELECT NOBS INTO :NUMBOBS FROM SASHELP.VTABLE
WHERE LIBNAME='WORK' AND MEMNAME='LOOP' ;
QUIT;

%END ;
%MEND CUTTOPVAL ;
SAS Super FREQ
Posts: 9,371

Hi:
For some general macro overviews -- on overall macro processing and SYMPUT (among other topics), perhaps these papers will prove easier to go through:
http://www2.sas.com/proceedings/sugi29/052-29.pdf
http://support.sas.com/resources/papers/proceedings11/119-2011.pdf
http://www.lexjansen.com/wuss/2006/CodersCorner/COD-Gustafson.pdf
http://www.nesug.org/proceedings/nesug98/code/p088.pdf

cynthia
SAS Employee
Posts: 121

Instead of adding a separate PROC SQL step, you could just modify the last data step as follows. Code additions are documented in comments:

DATA LOOP ;
/* Detect how many observations are in NOTDONE with nobs= */
SET NOTDONE nobs=NumObs;
/* Write the remining number of iterations to the NUMBOBS macro variable */
call symputx("NUMBOBS",NumObs-1);
IF _N_ = 1 THEN DELETE ;
RUN ;
Super User
Posts: 10,787