/********************************************************************/ /* NAME: CORRWT SYSTEM: MSCDC PGMR: BLODGETT */ /* FUNCTION: CONVERT CORRELATION LIST WITH WEIGHT VAR TO ONE WITH */ /* ALLOCATION FACTORS. */ /* STATUS: TEST UNDER AIX / SAS6.11 */ /* DOCUMENTATION: */ /* NOTES: CAN BE USED TO DO "AUTO-CORRELATION", OR AS AN EFFICIENT */ /* UTILITY TO GENERATE PERCENT-OF-TOTAL STATS. E.G. SPECIFY */ /* GEOCDS1=STATE,GEOCDS2=STATE COUNTY,WEIGHT=TOTPOP, RESULTS IN */ /* OUTPUT DATA SET WITH AFACT BEING PCT OF STATE POP IN EA COUNTY.*/ /* */ /********************************************************************/ /* UPDATE HISTORY: 2-11-91: ADDING LENGTH AND LABEL SPECS FOR AFACT. 8-29-94: Quoting references to parms &setin, &setout, &geocds1, &geocds2. 2-14-96: Adding xyopt to process centroids by taking weighted avgs. 3-13-96: Adding exitout feature to allow a user-exit macro to be inserted just prior to output statement (used by mable05). 3-31-96: Fixed problem with getting 0 divides when xyopt specified. 4-27-96: Working on 2-way allocation factors (afacts=2 option). Created series of parm aliases (g1, g2, wt, wtvar). New sort2 option allows specifying alternate output sort. New vorder option to avoid having corrwt reorder vars in output which it will now do by default. 5-01-96: Fix problem with sort2 option. */ /********************************************************************/ /* BEGIN MACRO DEFINITION */ /********************************************************************/ %MACRO CORRWT ( /* --CONVERT WEIGHTED CORRELATION LIST TO ALLOC---*/ REVDATE=01May96, /* ---DATE OF LAST REVISION--- */ SETIN=, /* REQUIRED NAME OF INPUT SAS DATA SET */ SETOUT=, /* NAME OF OUTPUT SAS DATA SET */ GEOCDS1= , /* REQUIRED LIST OF SOURCE GEOCDS. THE INPUT DATA SET (&SETIN) MUST BE SORTED BY THESE CODES */ GEOCDS2=, /* REQUIRED LIST OF GEOCDS FOR TARGET SYSTEM. THE ALLOCATION FACTOR WILL REPRESENT THE DECIMAL FRACTION OF GEOCDS1 THAT IS TO BE ALLOCATED TO GEOCDS2. FOR EXAMPLE: GEOCDS1=COUNTY TRACT80, GEOCDS2=TRACT90, WEIGHT=NSEGS,... FOR EACH VALUE OF COUNTY-TRACT80 CORRWT WILL SUM THE VALUES OF NSEGS. THEN FOR EACH SUB-GROUP BASED ON VALUES OF TRACT90 WITHIN THE COUNTY-TRACT80 GROUP THE SUM OF NSEGS WILL BE CALCULATED AND USED AS THE NUMER- ATOR OVER THE TRACT80 TOTAL TO DETERMINE THE VALUE OF THE ALLOCATION FACTOR. */ g1=, /* alias for geocds1 */ g2=, /* alias for geocds2 */ XYOPT=, /* null default says no coordinates. value of miles or latlon causes processing of coordinate vars on setin. A weighted avg will be taken for each geocds1/geocds2 combination and written to setout. Variable names are expected to be either intptlng,intptlat (if latlon specified) or xcentrm, ycentrm (if miles specified). */ latvar=intptlat, lonvar=intptlng, /* in conjunction with xyopt=latlon specified these 2 parms specify the names of the variables containing the lat and long coordinates in degrees */ exitout=, /* value of parm is the name of a macro that the user must insure is defined prior to invoking corrwt. That macro be referenced just prior to the output statement. it may contain a delete or return statement to avoid output*/ afacts=1, /* specify 0 to drop afact, specify afacts=2 to get two afact and afact2 the latter being the portion of the geocods2 area that is in geocds1. */ sort2=0, /* specify sort2=1 to have final output set sorted by &geocods2, &geocds1 instead of usual &geocds1, &geocds2*/ vorder=1, /* as of 4-27-96 corrwt will control order of variables in the output dataset unless you specify vorder=0 */ WEIGHT=, /* NAME OF VARIABLE ON &SETIN TO BE USED IN WEIGHTING. REQUIRED VARIABLE. IF _ONE_or 1 is SPECIFIED THEN EACH INPUT OBSERVATION WILL BE ASSIGNED A CONSTANT WEIGHT OF 1 */ wt=, /* alias for weight */ wtvar=, /* alias for weight */ KEEPWT=0, /* SPECIFY KEEPWT=1 TO KEEP WEIGHT TOTALS ON SETOUT */ IDVARS=, /* LIST OF ADDITIONAL VARS ON SETIN TO CARRY ON OUTPUT DATA SET. SHOULD BE VALUES UNIQUELY ASSOCIATED WITH VALUES OF THE GEOCODE VARIABLES */ LISTN=0, /* SPECIFY A POSITIVE VALUE TO HAVE THAT MANY OF THE OUTPUT OBSERVATIONS LISTED USINGA PUT _ALL_ STATEMENT. A DEBUGGING TOOL. */ DEBUG=0); /* END */ %PUT %STR( ); %PUT ***************************************************************; %PUT * CORRWT MACRO REV &REVDATE BEGIN EXECUTION *; %PUT * MISSOURI STATE CENSUS DATA CENTER *; %PUT ***************************************************************; %PUT %STR( ); %*--check for and use new aliases (4-27-96)--; %if %quote(&g1) ne %str() %then %let geocds1=&g1; %if %quote(&g2) ne %str() %then %let geocds2=&g2; %if %quote(&wt) ne %str() %then %let weight=&wt; %if %quote(&wtvar) ne %str() %then %let weight=&wtvar; %if %qupcase(&weight) eq %str(_ONE_) or %quote(&weight) eq 1 %then %do; %let weight=1; %let wtvar=; %end; %else %let wtvar=&weight; %*--so wtvar only refers to input vars; %if %quote(&wtvar) eq %str() and &keepwt %then %do; %put *** Warning: keepwt parm specified when no weight variable ***; %let keepwt=0; %end; %IF &DEBUG %THEN %DO; %PUT %STR( ); %PUT; %PUT *****PARAMETERS SPECIFIED*****; %PUT GEOCDS1 &GEOCDS1 (LIST OF GEOCODES TO BE ALLOCATED FROM); %PUT GEOCDS2 &GEOCDS2 (LIST OF GEOCODES TO BE ALLOCATED TO); %PUT WEIGHT= &WEIGHT (VARIABLE MEASURING INTERSECTION OF GEOCDS); %PUT IDVARS= &IDVARS (ID VARIABLES TO BE KEPT ON SETOUT); %PUT SETIN &SETIN (NAME OF INPUT SAS DATA SET); %PUT SETOUT= &SETOUT (NAME OF OUTPUT SAS DATA SET); %PUT XYOPT= &XYOPT (OPTION TO CARRY WEIGHTED AVG CENTROID ON OUTPUT); %PUT exitout= &exitout (user exit macro invoked prior to output); %put sort2 &sort2 (value of 1 means sort output by geocds2; %put afacts= &afacts (value of 2 means create afact2 - allocation; %put %str( ) factor relating the geocds2 geos to geocds1; %put vorder= &vorder (value of 1 - the default - say to reorder vars); %END; %LET ERR=0; %IF %quote(&SETIN)= %THEN %DO; %PUT ***REQUIRED PARM SETIN NOT SPECIFIED***; %LET ERR=1; %END; %IF %quote(&SETOUT)= %THEN %DO; %PUT ***REQUIRED PARM SETOUT NOT SPECIFIED***; %LET ERR=1; %END; %IF &WEIGHT = %THEN %DO; %PUT ***REQUIRED PARM WEIGHT NOT SPECIFIED***; %LET ERR=1; %END; %IF %quote(&GEOCDS1) = %THEN %DO; %PUT ***REQUIRED PARM GEOCDS1 NOT SPECIFIED***; %LET ERR=1; %END; %IF %quote(&GEOCDS2) = %THEN %DO; %PUT ***REQUIRED PARM GEOCDS2 NOT SPECIFIED***; %LET ERR=1; %END; %local xvar yvar; %let xvar=; %let yvar=; %IF %QUOTE(&XYOPT) NE %STR() %THEN %DO; %LET XYOPT=%UPCASE(&XYOPT); %if &xyopt=LATLON %then %do; %let xvar=&lonvar; %let yvar=&latvar; %end; %else %if &xyopt=MILES %then %do; %let xvar=xcentrm; %let yvar=ycentrm; %end; %else %do; %put &xyopt value for xyopt parm is invalid; %put %str( ) -- specify either "latlon" or "miles"; %let ERR=1; %end; %end; %IF &ERR %THEN %DO; %PUT; %PUT ***MACRO WILL NOT EXECUTE***; %GOTO ENDMAC; %END; %*--FOR BY STATMENTS WE NEED TO GET THE NAME OF THE LAST VARIABLE IN THE GEOCDS1 AND GEOCDS2 LISTS--; %LET NGEOS=1; %LET GEOCODE=%SCAN(&GEOCDS1,1); %LET LASTCD=&GEOCODE; %DO %WHILE(&LASTCD NE ); %LET NGEOS=%EVAL(&NGEOS+1); %LET LASTCD=%SCAN(&GEOCDS1,&NGEOS); %IF &LASTCD NE %THEN %LET GEOCODE=&LASTCD; %END; %IF &DEBUG %THEN %PUT **GEOCODE DETERMINED AS &GEOCODE; %LET NGEOS=1; %LET GEOCODE2=%SCAN(&GEOCDS2,1); %LET LASTCD=&GEOCODE2; %DO %WHILE(&LASTCD NE ); %LET NGEOS=%EVAL(&NGEOS+1); %LET LASTCD=%SCAN(&GEOCDS2,&NGEOS); %IF &LASTCD NE %THEN %LET GEOCODE2=&LASTCD; %END; %IF &DEBUG %THEN %PUT **GEOCODE2 DETERMINED AS &GEOCODE2; %if &afacts=2 %then %do; %*--calculate allocation factors from geocds2 to geocds1--; proc sort data=&setin(keep=&geocds1 &geocds2 &wtvar) out=_setin; by &geocds2 &geocds1; run; DATA _TOTALS2; SET _setin; BY &GEOCDS2; %IF &WEIGHT=1 %THEN %DO; RETAIN __ONE__ 1; %END; IF FIRST.&GEOCODE2 THEN _TOTAL=&WEIGHT; ELSE _TOTAL + &WEIGHT; IF LAST.&GEOCODE2 THEN OUTPUT; KEEP &GEOCDS2 _TOTAL; RUN; DATA _afacts2; %IF &WEIGHT=1 %THEN %DO; RETAIN __ONE__ 1; %END; SET _setin; BY &GEOCDS2 &GEOCDS1; IF FIRST.&GEOCODE2 THEN SET _TOTALS2; *--TO DEFINE _TOTAL--; IF FIRST.&GEOCODE THEN _TOTAL1=&WEIGHT; ELSE _TOTAL1 + &WEIGHT; IF LAST.&GEOCODE THEN DO; IF _TOTAL LE 0 THEN AFACT2=.; ELSE AFACT2=_TOTAL1/_TOTAL; OUTPUT; END; KEEP &GEOCDS1 &GEOCDS2 AFACT2; LENGTH AFACT2 4; LABEL AFACT2="&geocode2 to &geocode alloc factor"; FORMAT AFACT2 6.3; proc sort data=_afacts2; by &geocds1 &geocds2; run; %put *** _afacts2 dataset generated ***; %end; *<-------------processing to determine afact2 vars----; *--------Now do normal processing----------*; DATA _TOTALS; SET &SETIN; BY &GEOCDS1; %IF &WEIGHT=1 %THEN %DO; RETAIN __ONE__ 1; %END; IF FIRST.&GEOCODE THEN _TOTAL=&WEIGHT; ELSE _TOTAL + &WEIGHT; IF LAST.&GEOCODE THEN OUTPUT; KEEP &GEOCDS1 _TOTAL; RUN; %if &sort2 %then %str(data _setout; ); %else %do; DATA &SETOUT; %end; %IF &WEIGHT=1 %THEN %DO; RETAIN __ONE__ 1; %END; *--retain stmt added 4-27 to control order of vars on output set; %if &vorder %then %do; retain &geocds1 &geocds2 &idvars &xvar &yvar &wtvar afact; %end; SET &SETIN(KEEP=&IDVARS &GEOCDS1 &GEOCDS2 &xvar &yvar %IF &WEIGHT NE 1 %THEN &WEIGHT; ); BY &GEOCDS1 &GEOCDS2; IF FIRST.&GEOCODE THEN SET _TOTALS; *--TO DEFINE _TOTAL--; IF FIRST.&GEOCODE2 THEN _TOTAL2=&WEIGHT; ELSE _TOTAL2 + &WEIGHT; %if &xyopt ne %then %do; if first.&geocode2 then do; _xtotal=&weight*&xvar; _ytotal=&weight*&yvar; end; else do; _xtotal+ &weight*&xvar; _ytotal+ &weight*&yvar; end; if last.&geocode2 then do; if _total2 then do; *<---fix 3-31-96--; &xvar=_xtotal/_total2; &yvar=_ytotal/_total2; *<--weighted avgs; end; else do; &xvar=&xvar; &yvar=&yvar; *<---if weight is 0 use last obs-; end; end; %end; IF LAST.&GEOCODE2 THEN DO; %if &afacts=2 %then %do; set _afacts2(keep=&geocode2 afact2 rename=(&geocode2=_geo2_)); *--make sure codes are in synch--; if &geocode2 ne _geo2_ then do; file log; put '**** Problem: Check geocode on _afacts2 dataset does ' 'not match code on setout. Probable logic error*** '/ 'Contact John Blodgett (314) 516-6014 '/ '** Program aborting *** ' /_all_; abort 888; end; keep afact2; %end; IF _TOTAL LE 0 THEN AFACT=.; ELSE AFACT=_TOTAL2/_TOTAL; FORMAT AFACT 5.3; %IF &KEEPWT %THEN %STR( &WEIGHT=_TOTAL2;); %if &exitout ne %str() %then %&exitout; OUTPUT; %IF &LISTN %THEN %DO; _NOUT+1; IF _NOUT LE &LISTN THEN PUT _ALL_; %END; END; KEEP &GEOCDS1 &GEOCDS2 AFACT &IDVARS &xvar &yvar; %IF &KEEPWT %THEN %STR( KEEP &WEIGHT;); LENGTH AFACT 4; LABEL AFACT="&geocode to &geocode2 alloc factor"; FORMAT AFACT 6.3; %ENDMAC: %if &sort2 %then %do; run; *<---now do final sort by target geocodes-; proc sort data=_setout out=&setout; by &geocds2 &geocds1; run; %end; %MEND CORRWT ;