/***************************************************************** NAME: AGG SYSTEM: MSCDC PGMR: BLODGETT FUNCTION: AGGREGATE DATA AT ONE OR MORE NESTED LEVELS. ALLOWS FOR HANDLING MEANS/MEDIANS/PCTS. STATUS: Production under UNIX, Windows, MVS RELATED MODULES: Accesses the XPNDLST utility macro to get length of var list using dashes. will not use if user does not use dashes or if parms specifiying list lengths are used. uses the NVARLST macro to expand and count _numeric_ var list if aggvars=_nuemric_ (or aggvars=all) is specified. 5-17=05: We are using the varlist macro from D. Ward to expand value of _character_ for the idvars list NOTES: Under SAS v6 if the expanded "double-dash list" generated by the nvarlst macro when aggvars=all is specified goes over 200 characters the program would fail. A warning msg is written to the log but it would be easy to miss. Very unlikely to happen. ******************************************************************/ /* UPDATE HISTORY 02-10-92 JGB ADDING CODE TO USE PRE-STEP TO DETERMINE NAGGVARS IF NOT SPECIFIED (VIA PARM) AND AGGVARS LISTS IS _NUMERIC_ OR CONTAINS DOUBLE-DASH. 04-17-92 JGB ADDING NOTSORTD OPTION TO ALLOW AGGING WHEN DATA SET IS GROUPED BUT NOT SORTED BY SINGLE AGGBY VARIABLE. 09-01-93 JGB ADDED CHECK TO INSURE THAT AGGBY PARM SPECIFIED UNLESS GRAND=ONLY. 11-27-93 JGB FIXED PROBLEM REFERENCING &AGGIN INSTEAD OF &SETIN WHEN DETERMINE NUMERIC VARS IN PRE-STEP. ADDING CODE TO EDIT AGGVARS FROM _NUMERIC_ TO A DOUBLE DASH LIST FOR SUBSEQUENT PROCESSING. 12-04-98: JGB Allow grand=y or grand=n for yes/no. 5-14-99: Problem with aggvars=_numeric_ being fixed using new nvarlst macro to return expanded varlist and count. aggvars=all will now work - all will be changed to _numeric_. 3-22-02: Check for null value of naggvars and set to 0. 5-30-02: Adding linkout parm to allow user to code an output routine. 8-14-02: Making longer vars to hold variable names to reflect v7/v8 limits-. 10-28-02: Make meanwts an alias for mweights. 05-17-05: Adding check for idvars=_character_ and using varlist macro to assign a true variable list to the parm . */ /********************************************************************/ /* BEGIN MACRO DEFINITION */ /********************************************************************/ %MACRO AGG( REVDATE=28Oct02, /* DATE OF LAST REVISION <===================== */ SETIN=_LAST_, /* SPECIFIES NAME OF INPUT SAS DATA SET. */ AGGIN=, /* ALIAS FOR SETIN */ SETOUT=AGGOUT, /* NAME OF AGGREGATED OUTPUT SAS D.S. */ AGGOUT=, /* ALIAS FOR SETOUT */ AGGBY=, /* LIST OF ONE OR MORE VARS WHOSE VALUES WILL FORM THE AGGREGATION COHORTS. */ BYVARS=, /* ALIAS FOR AGGBY */ NOTSORTD=0, /* SPECIFY NOTSORTD=1 IF SETIN IS NOT SORTED BY THE AGGBY VARS BUT YOU WANT TO WANT TO AGGREGATE IN UNSORTED GROUPS ANYWAY */ AGGLVL=1, /* # VARS IN AGGBY LIST, NUMBERED FR. RIGHT, WHICH WILL TRIGGER OUTPUT WHEN BREAK OCCURS. IF AGGBY=C T B AND AGGLVL=2 THEN OUTPUT OCCURS WHEN B (WITH _LVL_=1) OR T (WITH _LVL_=2) CHANGES (BREAKS) */ AGGLVLS=, /* ALIAS FOR AGGLVL */ AGGVARS=, /* REQUIRED. LIST OF NUMERIC VARIABLES ON SETIN TO BE AGGREGATED (SUMMED) OVER EACH AGGBY-COHORT. */ VARS=, /* ALIAS FOR AGGVARS */ NAGGVARS=0, /* IF AGGVARS CONTAINS _NUMERIC_ OR -- LISTS THEN AGG HAS TO RUN EXTRA STEP(s) TO DETERMINE THE NUMBER OF VARS IN THE AGGVARS LIST. BUT IF YOU SPECIFY THIS PARM AGG WILL USE IT INSTEAD (WITHOUT CHECKING - BE CAREFUL */ NUMS=, /* LIST OF NUMERATORS TO BE USED IN CALCULATING PERCENTAGES AND/OR RATIOS. SEE DENOMS, NEXT. */ NNUMS=0, DENOMS=, /* EITHER A LIST OF VARIABLES TO BE USED AS THE DENOMINATORS FOR CALCULATING PERCENTAGES AND/OR RATIOS, OR A SINGLE VAR TO BE USED AS THE DENOMINATOR FOR ALL P/R S. */ DENS=, /* ALIAS FOR DENOMS */ NDENOMS=0, PCTS=,RATIOS=, /* THESE ARE MUTUALLY EXCLUSIVE ITEMS. IF SPECIFIED THEN NUMS AND DENOMS MUST ALSO BE SPECIFIED. SEE DOC. FOR DETAILS */ PERCENTS=, /* ALIAS FOR PCTS */ NPCTS=0,NRATIOS=0, MEANS=, /* SEE DOCUMENTATION */ NMEANS=0, MEDIANS=, /* ALIAS FOR MEANS.*/ MWEIGHTS=, /* A LIST OF VARIABLES USED TO WEIGHT THE VARS IN MEANS. OR IT CAN BE A SINGLE VARIABLE USED TO WEIGHT ALL THE VARS */ meanwts=, /* Alias for mweights */ NMWTS=0, SLCTEDIT=, /* NAME OF USER-EXIT MACRO THAT CAN BE INSERTED AFTER SET STATEMENT ON SETIN. */ linkout=0, /* specify linkout=1 to indicate replacing output statements with "link output" stmts. User must then finish the step with a return stmt and then the output: stmt, some code that includes output statements, and a return to end the linked-to routine */ FILTER=, IDVARS=, /* LIST OF ADDITIONAL VARIABLES TO BE KEPT ON THE OUTPUT DATA SET. */ IDS=, /* ALIAS FOR IDVARS */ NIDVARS=0, DROPVARS=, /* LIST OF VARIABLES TO BE DROPPED FROM FINAL DATA SET*/ DROP=, /* ALIAS FOR DROPVARS */ NDROPS=0, GRAND=NO, /* DEFAULT SAYS NOT TO CREATE A GRAND TOTAL OBSERVATION. OTHER VALUES RECOGNIZED ARE 'YES' AND 'ONLY'.*/ FACVAR=, /* CAN BE USED TO SPECIFY THE NAME OF A NUMERIC VARIABLE ON THE INPUT DATA SET WHICH CAN BE USED TO FACTOR THE DATA PRIOR TO AGGREGATING. USEFUL FOR DOING AGG APPLICATIONS WHERE YOU ADD ALL OF ONE AREA, HALF OF ANOTHER AND THEN SUBTRACT ONE THIRD OF ANOTHER. ALSO USEFUL FOR DOING "COORELATE AND AGGREGATE" APPLICATIONS. */ FILLBY= , /* SPECIFY CHARACTER TO BE USED AS "FILL" FOR AGGBY VARS IN SUMMARY OUTPUT OBSERVATIONS WHERE THEY ARE NOT ONE OF THE RELEVANT CLASS VARS. SPECIFY HIGH TO GET HIGHEST CHARACTER VALUE. MAY ONLY WORK WITH CHARACTER TYPE BYS OF MAX LENGTH 32 */ NODUPS=0, /* SPECIFY NODUPS=1 TO ELIMINATE REDUNDANT HIGHER LEVEL SUMMARIES */ DEBUG=0); /* END */ %PUT %STR( ); %PUT ***************************************************************; %PUT * AGG Macro Rev. &REVDATE Begin Execution *; %PUT * Missouri Census Data Center *; %PUT ***************************************************************; %PUT %STR( ); %***************************************************************** * EDIT AND VERIFY PARAMETERS. * *****************************************************************; %LOCAL ERR; %LET ERR=0; %*--IF ANY ALIAS NAMES ARE USED THEN ASSIGN THOSE VALUES TO THE TRUE PARM NAME; %IF %QUOTE(&AGGIN) NE %THEN %LET SETIN=&AGGIN; %IF %QUOTE(&AGGOUT) NE %THEN %LET SETOUT=&AGGOUT; %IF %QUOTE(&BYVARS) NE %THEN %LET AGGBY=&BYVARS; %IF %QUOTE(&VARS) NE %THEN %LET AGGVARS=&VARS; %IF %QUOTE(&AGGLVLS) NE %THEN %LET AGGLVL=&AGGLVLS; %IF %QUOTE(&IDS) NE %THEN IDVARS=&IDS; %IF %QUOTE(&MEDIANS) NE %THEN %LET MEANS=&MEDIANS; %if %quote(&meanwts) ne %then %let mweights=&meanwts; %IF %QUOTE(&DROP) NE %THEN %LET DROPVARS=&DROP; %IF %QUOTE(&DENS) NE %THEN %LET DENOMS=&DENS; %IF %QUOTE(&PERCENTS) NE %THEN %LET PCTS=&PERCENTS; %IF %QUOTE(&PCTS) NE AND %QUOTE(&RATIOS) NE %THEN %DO; %PUT ***MUTUALLY EXCLUSIVE PARMS RATIOS AND PCTS BOTH SPECIFIED***; %LET ERR=1; %END; %LET GRAND=%UPCASE(&GRAND); %IF %STR(&GRAND)=YES or %str(&grand)=Y %THEN %LET GRAND=1; %ELSE %IF %STR(&GRAND)=NO or %str(&grand)=N %THEN %LET GRAND=0; %ELSE %IF %STR(&GRAND)=ONLY %THEN %LET AGGBY=; %IF %QUOTE(&AGGVARS) EQ %THEN %DO; %PUT ***REQUIRED PARM AGGVARS WAS NOT SPECIFIED***; %LET ERR=1; %END; %else %let aggvars=%qupcase(&aggvars); %if &aggvars=ALL %then %let aggvars=_NUMERIC_; %IF %QUOTE(&AGGBY) EQ AND &GRAND NE ONLY %THEN %DO; %PUT ***REQUIRED PARM AGGBY WAS NOT SPECIFIED***; %LET ERR=1; %END; %IF %QUOTE(%UPCASE(&NODUPS))=YES OR %QUOTE(%UPCASE(&NODUPS))=Y %THEN %LET NODUPS=1; %IF &DEBUG %THEN %DO; %PUT %STR( ); %PUT; %PUT *****PARAMETERS SPECIFIED*****; %PUT (NAMES IN PARENTHESES ARE ALIASES); %PUT SETIN(AGGIN)= &SETIN (INPUT DATA SET); %PUT SETOUT(AGGOUT)= &AGGOUT (OUTPUT DATA SET); %PUT AGGBY(BYVARS)= &AGGBY (AGGREGATION BY VARIABLES); %PUT AGGLVL(AGGLVLS)= &AGGLVL (NUMBER OF LEVELS OF AGGREGATION); %PUT AGGVARS(VARS)= &AGGVARS (VARIABLES ON SETIN TO AGGREGATE); %if &naggvars eq %then %let naggvars=0; %IF &NAGGVARS %THEN %PUT NAGGVARS= &NAGGVARS (NUMBER OF VARIABLES IN AGGVARS LIST); %PUT NUMS= &NUMS (NUMERATOR VARIABLES); %IF &NNUMS %THEN %PUT NNUMS= &NNUMS (NUMBER OF VARIABLES IN NUMS LIST); %PUT DENOMS(DENS)= &DENOMS (LIST OF DENOMINATORS); %IF &NDENOMS %THEN %PUT NDENOMS= &NDENOMS (NUMBER OF VARIABLES IN DENOMS LIST); %IF %STR(&PCTS) NE %THEN %PUT PCTS= &PCTS (LIST OF PERCENTAGE VARIABLES TO CALCULATE); %IF %STR(&RATIOS) NE %THEN %PUT RATIOS= &RATIOS (LIST OF RATIO VARIABLES TO CALCULATE); %PUT MEANS(MEDIANS)= &MEANS (MEAN/MEDIAN VARS TO BE AGGREGATED); %IF &NMEANS %THEN %PUT NMEANS= &NMEANS (NUMBER OF VARIABLES IN MEANS LIST); %PUT MWEIGHTS= &MWEIGHTS (LIST OF WEIGHT VARIABLES FOR MEANS); %IF &NMWTS %THEN %PUT NMWTS= &NMWTS (NUMBER OF VARIABLES IN MWEIGHTS LIST); %IF %STR(&DROPVARS) NE %THEN %PUT DROPVARS= &DROPVARS (VARIABLES TO DROP FROM OUTPUT DATA SET); %PUT SLCTEDIT(FILTER)=&SLCTEDIT (SELECT/EDIT USER-EXIT MACRO NAME); %PUT IDVARS(IDS)= &IDVARS (ID VARIABLES TO KEEP ON AGGOUT); %PUT GRAND= &GRAND (GRAND TOTALS OPTION); %IF &FACVAR NE %THEN %PUT FACVAR= &FACVAR (NAME OF VARIABLE USED TO FACTOR DATA); %PUT FILLBY= &FILLBY (FILLER CHARACTER FOR AGGBY VARIABLES); %PUT NODUPS= &NODUPS (OPTION TO OMIT REDUNDANT HIGHER LEVEL SUMS); %PUT ***END PARM LIST***; %PUT; %END; %MACRO LL(LIST); %*--UTILITY SUB-MACRO TO RETURN THE LENGTH OF A LIST; %LET L=&LIST; %LOCAL ANS S; %IF %QUOTE(&L) EQ %THEN 0; %ELSE %IF %INDEX(&L,%STR(-)) EQ 0 %THEN %DO; %LET ANS=2; %LOOP: %LET S=%SCAN(&L,&ANS); %IF %STR(&S) NE %THEN %DO; %LET ANS=%EVAL(&ANS + 1); %GOTO LOOP; %END; %LET ANS=%EVAL(&ANS-1); &ANS %END; %ELSE %DO; %*--IF LIST CONTAINS INTERVALS USE XPNDLST UTILITY MACRO; %LET ANS=0; %LET DUMMY=%XPNDLST(&L,ANS); &ANS %END; %MEND LL; %LOCAL I J RP; %LOCAL NAGGBY; %*---NEW CODE TO DETERMINE NAGGVARS FROM DATA SET IN SOME CASE---*; %LOCAL AGGVARQ; %LET AGGVARQ=%QUOTE(&AGGVARS); %if %superq(idvars)=%str(_character_) %then %do; %let idvars=%varlist(_character_,&setin); %let nidvars=%ll(&idvars); %end; %IF &NAGGVARS=0 AND %INDEX(&AGGVARQ,%STR(--)) %THEN %DO; %PUT ***DATA STEP WILL BE USED TO COUNT NUMBER OF AGGVARS***; DATA _NULL_; SET &SETIN; ARRAY _AGGVAR_(*) &AGGVARS; %*---CODE RELATED TO VNAME CALLS TO EDIT AGGVARS WHEN _NUMERIC_ SPECIFIED ADDED 11-27-93, JGB---*; length _name1 _namelst $32; *<==new, 8/02 for v8 upgrade--; RETAIN _NAME1 _NAMELST ' '; DO _I_=1 TO DIM(_AGGVAR_); NAGGVARS+1; IF _I_=1 THEN CALL VNAME(_AGGVAR_(_I_),_NAME1); END; %IF &AGGVARQ=_NUMERIC_ %THEN %DO; LENGTH _EVARLST $18; CALL VNAME(_AGGVAR_(NAGGVARS),_NAMELST); IF NAGGVARS GT 1 THEN _EVARLST=TRIM(_NAME1)||'-numeric-'||_NAMELST; ELSE _EVARLST=_NAME1; CALL SYMPUT('AGGVARS',_EVARLST); %END; CALL SYMPUT('NAGGVARS',NAGGVARS); PUT NAGGVARS=; STOP; RUN; %PUT **VALUE FOR NAGGVARS DETERMINED BY DATA STEP IS &NAGGVARS; %END; %else %if &aggvarq=%str(_NUMERIC_) %then %do; %nvarlst(&setin,aggvars,naggvars); %*--new utility macro 5-99--; %put nvarlst macro was used to redefine parms aggvars and naggvars as; %put &aggvars &naggvars; %end; %IF &NAGGVARS EQ 0 %THEN %LET NAGGVARS=%LL(&AGGVARS); %IF &NAGGVARS=0 %THEN %DO; %LET ERR=1; %PUT ***REQUIRED PARM AGGVARS NOT SPECIFIED***; %END; %LET NAGGBY=%LL(&AGGBY); %LET J=&NAGGBY; %IF &AGGLVL GT 0 %THEN %DO I=1 %TO &NAGGBY; %*--PARSE THE AGGBY LIST TO GET NAMES OF VARS TO USE DURING AGG; %LET AGGBY&I=%SCAN(&AGGBY,&J); %LET J=%EVAL(&J -1); %IF &DEBUG %THEN %PUT AGGBY&I= &&AGGBY&I; %END; %IF %STR(&GRAND)=ONLY %THEN %LET AGGLVL=0; %ELSE %IF %STR(&AGGLVL) EQ %THEN %LET AGGLVL=&NAGGBY; %ELSE %IF &AGGLVL GT &NAGGBY %THEN %DO; %LET ERR=1; %PUT ***&AGGLVL IS INVALID VALUE FOR AGGLVL PARM***; %END; %IF &NNUMS EQ 0 %THEN %LET NNUMS=%LL(&NUMS); %IF &NDENOMS EQ 0 %THEN %LET NDENOMS=%LL(&DENOMS); %IF &NPCTS EQ 0 %THEN %LET NPCTS=%LL(&PCTS); %IF &NRATIOS EQ 0 %THEN %LET NRATIOS=%LL(&RATIOS); %IF &NNUMS NE 0 %THEN %IF &NDENOMS NE &NNUMS %THEN %DO; %IF &NDENOMS NE 1 %THEN %DO; %LET ERR=1; %PUT ***DENOMS LIST AND NUMS LIST ARE NOT SAME LENGTH**; %END; %ELSE %DO I=2 %TO &NNUMS; %IF &I EQ 2 %THEN %LET D1=&DENOMS; %LOCAL D1; %LET DENOMS=&DENOMS &D1; %END; %END; %IF &NNUMS NE 0 AND (&NPCTS=0 AND &NRATIOS=0) OR (&NNUMS EQ 0 AND (&NPCTS OR &NRATIOS)) %THEN %DO; %LET ERR=1; %PUT ***INCONSISTENT SPECS FOR NUMS, DENOMS, PCT AND RATIOS***; %END; %*--AT THIS POINT WE USE THE RATIOS VARS FOR EITHER PCTS OR RATIOS AND JUST SET A FLAG TO TELL US HOW TO CALCULATE--; %IF &NPCTS %THEN %DO; %LET NRATIOS=&NPCTS; %LET RATIOS=&PCTS; %LET RP=P; %END; %ELSE %IF &NRATIOS %THEN %LET RP=R; %ELSE %LET RP= ; %IF &NMEANS EQ 0 %THEN %LET NMEANS=%LL(&MEANS); %IF &NMWTS EQ 0 %THEN %LET NMWTS=%LL(&MWEIGHTS); %IF &NMEANS NE 0 %THEN %IF &NMWTS NE &NMEANS %THEN %DO; %IF &NMWTS NE 1 %THEN %DO; %LET ERR=1; %PUT ***MEANS LIST AND MWEIGHTS LIST ARE NOT SAME LENGTH**; %END; %ELSE %DO I=2 %TO &NMEANS; %IF &I=2 %THEN %LET D1=&MWEIGHTS; %LET MWEIGHTS=&MWEIGHTS &D1; %END; %END; %IF %STR(&GRAND) EQ ONLY %THEN %LET GRAND=1; %*--RECODE SO WE CAN REFERENCE AS A LOGICAL VAR; %LOCAL FACTOR; %IF &FACVAR NE %THEN %LET FACTOR=%STR( * ) &FACVAR; %ELSE %LET FACTOR= ; %IF &ERR=1 %THEN %DO; %PUT; %PUT; %PUT ****AGG MACRO WILL NOT GENERATE CODE DUE TO ERRORS NOTED; %GOTO ENDMAC; %END; %IF &DEBUG %THEN %PUT ****PARM VERIFICATION PHASE COMPLETE****; %****************************************************************** * BEGIN GENERATION OF CODE TO PERFORM AGGREGATION. IT WILL BE * * IMPLEMENTED IN A SINGLE DATA STEP. * *******************************************************************; DATA &SETOUT; LENGTH _LVL_ 3 _NAG_ 4; LABEL _LVL_='SUMMARY LEVEL CODE' _NAG_='# OF OBS AGGREGATED'; SET &SETIN(KEEP=&AGGBY &AGGVARS &IDVARS &NUMS &DENOMS &MEANS &MWEIGHTS &FACVAR) END=EODAGGIN; BY &AGGBY %IF %QUOTE(&NOTSORTD) EQ %STR(1) OR %QUOTE(&NOTSORTD) EQ NOTSORTED %THEN %STR( NOTSORTED ); ; %IF &SLCTEDIT NE %STR() %THEN %&SLCTEDIT; RETAIN; %IF %QUOTE(%UPCASE(&FILLBY))=HIGH %THEN %DO; RETAIN _FILLBY "FF"X; %END; %ELSE %IF %QUOTE(&FILLBY) EQ %THEN %DO; RETAIN _FILLBY " "; %END; %ELSE %DO; LENGTH _FILLBY $32; IF _FILLBY=' ' THEN _FILLBY=REPEAT("&FILLBY",31); %END; DROP _FILLBY; %IF &FACVAR NE %THEN %DO; *--IF FACTOR VARIABLE IS MISSING, ASSUME VALUE OF 1; IF &FACVAR= . THEN &FACVAR=1; %END; *--USE 2-DIMENSIONAL ARRAYS TO HOLD TOTALS. 1ST SUBSCRIPT REFERS TO THE SUMMARY LEVEL, THE 2ND REFERS TO THE AGGVAR NUMBER. IF GRAND TOTALS ARE REQUESTED THEY ARE PUT IN AN EXTRA ROW OF THE _SUMS_ ARRAY--; %LOCAL NROWS; %IF &GRAND %THEN %LET NROWS=%EVAL(&AGGLVL+1); %ELSE %LET NROWS=&AGGLVL; %LOCAL NVARS; %LET NVARS= &NAGGVARS; RETAIN _NROWS &NROWS _NVARS &NVARS; DROP _NROWS _NVARS; DROP _J_ ; %IF %STR(&DROPVARS) NE %THEN %DO; DROP &DROPVARS; %END; %LOCAL NMIDS; %LET NMIDS=%EVAL(&NMEANS + &NNUMS); *--WE SET UP SEPARATE ARRAYS TO DO DOUBLE AGGREGATION OF VARS INVOLVED IN WEIGHTED-MEANS OR PCT/RATIOS. THIS ALLOWS US TO HANDLE THE PROBLEMS OF ONE OF THESE VARS BEING MISSING FOR A CASE; %IF &NMIDS GT 0 %THEN %DO; %IF %STR(&DROPVARS) EQ %THEN %DO; %PUT ****WARNING: VARIABLES APPEARING IN NUMS, DENOMS OR MWEIGHTS; %PUT LISTS WILL NOT BE AGGREGATED UNLESS THEY ALSO APPEAR IN THE; %PUT AGGVARS LIST. USE THE DROPVARS PARM TO OMIT THEM FROM THE ; %PUT OUTPUT DATA SET.; %END; %*--IMPLICIT ARRAYS BEING USED FOR _MIDS_ AND _MIDS2_ TO AVOID BUG IN SAS606 INVOLVING REPEATED VARIABLES IN EXPLICIT ARRAYS--; ARRAY _MIDS_(&NMIDS) &NUMS &MEANS; ARRAY _MIDS2_(&NMIDS) &DENOMS &MWEIGHTS; ARRAY _MSUMS_(&NROWS,&NMIDS,2) _TEMPORARY_; %END; ARRAY _AGGVRS_ (&NVARS) &AGGVARS; ARRAY _SUMS_(&NROWS,&NVARS) _TEMPORARY_; ARRAY _FREQS_(&NROWS) _TEMPORARY_; %IF &NNUMS %THEN %DO; ARRAY _RATIOS_ (&NNUMS) &RATIOS; %END; %IF &NMEANS %THEN %DO; %LET XLOW=%EVAL(&NNUMS + 1); ARRAY _MEANS_ (&XLOW : &NMIDS) &MEANS; %END; %IF &GRAND %THEN %DO; IF _N_=1 THEN DO _J_=1 TO &NVARS; _SUMS_(&NROWS,_J_)=.; END; %END; *******************************************************************; * AGG INITIALIZATION CODE (FIRST.AGGBY PROCESSING) *; *******************************************************************; %DO I=1 %TO &AGGLVL; %*--AGGLVL MIGHT BE 0 (GRAND ONLY); IF FIRST.&&AGGBY&I THEN DO; %IF &I EQ 1 %THEN %DO; _FREQS_(1)=1; DO _J_=1 TO &NVARS; _SUMS_(1,_J_)= _AGGVRS_(_J_) &FACTOR; *--ASSIGN FIRST OCCURRENCE--; END; %IF &NMIDS %THEN %DO; DO _J_=1 TO &NMIDS; IF _MIDS2_(_J_)=. THEN _MSUMS_(1,_J_,1)=.; ELSE _MSUMS_(1,_J_,1)=_MIDS_(_J_) &FACTOR; IF _MIDS_(_J_)=. THEN _MSUMS_(1,_J_,2)=.; ELSE _MSUMS_(1,_J_,2)=_MIDS2_(_J_) &FACTOR; %IF &NMEANS %THEN %DO; IF _J_ GT &NNUMS THEN _MSUMS_(1,_J_,1)=_MIDS_(_J_)* _MIDS2_(_J_) &FACTOR; *--WEIGHT MEAN-; %END; END; %END; %IF &AGGLVL EQ 1 %THEN %STR(GOTO CKBREAK;); %ELSE %DO; _AGG=0; DROP _AGG; %END; %END; %ELSE %DO; _FREQS_(&I)=0; DO _J_=1 TO &NVARS; _SUMS_(&I,_J_)=.; END; %IF &NMIDS %THEN %DO; DO _J_=1 TO &NMIDS; _MSUMS_(&I,_J_,1)=.; _MSUMS_(&I,_J_,2)=.; END; %END; %END; END; %END; %*--I = 1 TO AGGVAL. INITIALIZATION; ******************************************************************; * THIS IS ACTUAL AGGREGATION PROCESSING, EXECUTED FOR EACH INPUT *; * OBSERVATION. WE AGG AT LOWEST LEVEL HERE. *; ******************************************************************; *-- TWO TRICKY ITEMS TO WATCH HERE: WE DO NOT AGG. FIRST OBS AT LOWEST LEVEL (WE ASSIGN IT DURING INIT PROCESSING, ABOVE.) WHEN DEALING WITH WITH MEANS/MEDIANS, RATIOS/PERCENTS WE HAVE TO BE CAREFUL NOT TO COUNT (I.E. AGGREG) THE VALUE OF ONE IF THE CORRESPONDING ITEM IS MISSING; %IF &AGGLVL GT 1 %THEN %DO; IF _AGG=0 THEN DO; _AGG=1; GOTO CKBREAK; END; %END; _FREQS_(1)+1; DO _J_=1 TO &NVARS; IF _AGGVRS_(_J_) NE . THEN _SUMS_(1,_J_) + _AGGVRS_(_J_) &FACTOR; END; %IF &NMIDS %THEN %DO; DO _J_=1 TO &NMIDS; IF _MIDS2_(_J_) NE . AND _MIDS_(_J_) NE . THEN DO; _MSUMS_(1,_J_,2) + _MIDS2_(_J_) &FACTOR; IF _J_ LE &NNUMS THEN _MSUMS_(1,_J_,1) + _MIDS_(_J_) &FACTOR; ELSE _MSUMS_(1,_J_,1) + _MIDS2_(_J_)*_MIDS_(_J_) &FACTOR; END; END; %END; CKBREAK: *******************************************************************; * BREAK PROCESSING. HIGHER LEVEL AGGREGATION, FINAL UNWEIGHTING *; * AND/OR RATIO/PERCENT CALUCATIONS, AND OUTPUTTING TAKE PLACE HERE*; *******************************************************************; %LOCAL IPI; %DO I=1 %TO &AGGLVL; IF LAST.&&AGGBY&I THEN DO; %LET IP1=%EVAL(&I + 1); *--FOR EACH AGG VAR, ADD TO NEXT HIGHER LEVEL AND MOVE TO OUTPUT DATA VECTOR. PROCESS MEANS, PERCENTS, RATIOS, ETC--; DO _J_=1 TO &NVARS; %IF &IP1 LE &NROWS %THEN %DO; _SUMS_(&IP1,_J_) + _SUMS_(&I,_J_); %END; _AGGVRS_(_J_) = _SUMS_(&I,_J_); END; %IF &IP1 LE &NROWS %THEN %DO; _FREQS_(&IP1) + _FREQS_(&I); *--COUNT OBSERVATIONS AGGREGATED; %END; %IF &IP1 LE &NROWS AND &NMIDS %THEN %DO; *--AGGREGATE SPECIAL MEAN/RATIO SUM VARS--; DO _J_=1 TO &NMIDS; _MSUMS_(&IP1,_J_,1) + _MSUMS_(&I,_J_,1); _MSUMS_(&IP1,_J_,2) + _MSUMS_(&I,_J_,2); END; %END; %IF &NNUMS %THEN %DO; *--PROCESS RATIOS/PERCENTS--*; DO _J_ = 1 TO &NNUMS; %LOCAL PFACTR; %IF &RP=R %THEN %LET PFACTR= ; %ELSE %LET PFACTR=%QUOTE(*100); IF _MSUMS_(&I,_J_,2) GT 0 THEN _RATIOS_(_J_)= _MSUMS_(&I,_J_,1) &PFACTR/_MSUMS_(&I,_J_,2); ELSE _RATIOS_(_J_)=.; END; %END; %IF &NMEANS %THEN %DO; *--PROCESS WEIGHTED MEANS/MEDIANS--*; %IF &NNUMS %THEN %LET J1=%EVAL(&NNUMS+1); %ELSE %LET J1=1; DO _J_= &J1 TO &NMIDS; IF _MSUMS_(&I,_J_,2) GT 0 THEN _MEANS_(_J_)= _MSUMS_(&I,_J_,1)/_MSUMS_(&I,_J_,2); ELSE _MEANS_(_J_)=.; END; %END; _LVL_=&I; _NAG_=_FREQS_(&I); *-----------WRITE THE AGGREGATED OBSERVATION------------*; %IF &NODUPS AND &I GT 1 %THEN %DO; %*--SUPPRESS "DUPLICATE" SUMMARIES IF NODUPS SPECIFIED-; IF _FREQS_(&I) GT _FREQS_(%EVAL(&I-1)) THEN %END; %if &linkout %then %str(link ); OUTPUT; &&AGGBY&I=_FILLBY;*--SET AGGBY VAR TO FILLER VALUE; END; *--LAST.AGGBY PROCESSING--; %END; %*--MACRO LOOP OVER AGGBY LEVELS; %IF &DEBUG EQ 2 %THEN %DO; *-------DIAGNOSTIC LISTINGS---------*; FILE LIST LINESIZE=80 ; PUT /_N_= _ALL_; DROP _II_ ; DO _II_=1 TO &NROWS; PUT _II_= 'FREQS(I)=' _FREQS_(_II_) 4. / '_SUMS_:'; DO _J_=1 TO &NVARS; PUT +1 _SUMS_(_II_,_J_) 4. @; END; PUT; %IF &NMIDS %THEN %DO; PUT 'MSUMS:'; DO _KK_=1 TO 2; DROP _KK_; DO _J_=1 TO &NMIDS; PUT _MSUMS_(_II_,_J_,_KK_) 5. @; END; PUT; END; %END; END; %END; %IF &GRAND EQ 0 %THEN %GOTO ENDMAC; IF NOT EODAGGIN THEN RETURN; *--BUILD GRAND TOTALS OUTPUT RECORD AND OUTPUT--*; _LVL_=99; *--NOTE SPECIAL CODE TO DENOTE GRAND TOTALS--; _NAG_=_FREQS_(&NROWS); %LET NIDVARS=%LL(&IDVARS); %IF &AGGLVL GT 0 %THEN %DO I=1 %TO &NIDVARS; %SCAN(&IDVARS,&I) = ' '; %END; %DO I=1 %TO &NAGGBY; &&AGGBY&I=_FILLBY; %END; DO _J_=1 TO &NVARS; _AGGVRS_(_J_) = _SUMS_(&NROWS,_J_); END; %IF &NNUMS %THEN %DO; *--PROCESS RATIOS/PERCENTS--*; DO _J_ = 1 TO &NNUMS; %IF &RP=R %THEN %LET FACTOR= ; %ELSE %LET FACTOR=%QUOTE(*100); IF _MSUMS_(&NROWS,_J_,2) GT 0 THEN _RATIOS_(_J_)= _MSUMS_(&NROWS,_J_,1) &FACTOR/_MSUMS_(&NROWS,_J_,2); ELSE _RATIOS_(_J_)=.; END; %END; %IF &NMEANS %THEN %DO; *--PROCESS WEIGHTED MEANS/MEDIANS--*; %IF &NNUMS %THEN %LET J1=%EVAL(&NNUMS+1); %ELSE %LET J1=1; DO _J_= &J1 TO &NMIDS; IF _MSUMS_(&NROWS,_J_,2) GT 0 THEN _MEANS_(_J_)= _MSUMS_(&NROWS,_J_,1)/_MSUMS_(&NROWS,_J_,2); ELSE _MEANS_(_J_)=.; END; %END; *-----------WRITE THE GRAND TOTALS OBSERVATION------------*; %if &linkout %then %str(link ); OUTPUT; %ENDMAC: %MEND AGG;