source: main/adopters/hi/trunk/src/main/backend_qModules/3.0/qModules30/brfss/SurveyAARateDist9plus.sas @ 25229

Last change on this file since 25229 was 25229, checked in by LoisHaggard_STG, 3 months ago

HI 3.0 backend/qModules30 updated BRFSS AARate.sas file to have correct suppression value attribute name. Other file just had a typo.

File size: 16.9 KB
Line 
1**********************************************************************;
2* Program filename: TotalSurvAgeBRFSS.sas                             ;
3*                                                                     ;
4* This file is "included" in each BRFSS indicator .def file for AA    ;
5* rates. The macro variables (varname, weight) are also set in the    ;
6* .def file. The %FocusLevel% variable is set in the IBIS Module.xml  ;
7* file as a filter exclude variable. This allows the user to select   ;
8* whether to calculate the at-risk percentage (%VarLevel=1) or the    ;
9* not-at-risk percentage (%VarLevel=2).                               ;
10*                                                                     ;
11* Missing set to . for all indicator and dimension vars               ;
12*                                                                     ;
13**********************************************************************;
14
15OPTIONS MPRINT MLOGIC MLOGICNEST SYMBOLGEN SPOOL SOURCE2 SUMSIZE=138M PAGESIZE=4000 LINESIZE=MAX;
16
17**********************************************************************************************;
18* CODE FOR ADJUSTING FOR MULTIPLE YEARS. ONLY NEEDED IF PRESENTING POPULATION COUNT ESTIMATES.;
19* If cross1 and cross2 are not equal to year, then _llcpwt is divided by the number of years  ;
20* the user selects                                                                            ;
21**********************************************************************************************;
22 
23/* proc print data=tmp (obs=10); run; */
24
25proc freq data=tmp;
26   tables year / out=yrfreq noprint;
27   run;
28   proc print data=yrfreq;
29        title1 ' '; title2 'yrfreq';
30        run;
31 
32 proc summary data=yrfreq;
33        class Year;
34        output out=yrnum n(year)=nyears;
35           proc print data=yrnum;
36                title1 ' '; title2 'yrnum';
37        run;
38
39data yrnum; set yrnum;
40        if year=.;
41        keep year nyears;
42           proc print data=yrnum;
43        title1 ' '; title2 'yrnum only .';
44run;   
45       
46proc sort data=tmp; by year; run;
47
48        proc sql;
49                create table tmpyrwgt as
50                select tmp.*, yrnum.nyears
51                from tmp, yrnum
52        quit;
53   
54 data tmp;
55     set tmpyrwgt;
56         if upcase(%cross1%) ^=YEAR
57         ?cross2? and upcase(%cross2%) ^=YEAR
58         then
59     _llcpwt=_llcpwt/nyears;
60   run;
61   
62/*proc print data=tmp (obs=10);
63        title1 ' '; title2 'checktmp .'; run;
64*/   
65
66/**** SURVEYMEANS*************************************************************;
67* Run the SURVEYMEANS proc with Age BRFSS in domain statement.                ;
68* No cross1 or cross2, run this first to get the totals.                      ;
69******************************************************************************;
70*/
71
72%macro ageadjrt(varname,weight,Focuslevel);
73
74 title1 '***************************************************************';
75 title2 'SURVEYMEANS proc (AgeBRFSS in domain statement and no cross vars)';
76 proc surveymeans data=tmp nobs sum mean stderr;
77        var &varname.;
78        class &varname.;
79        strata ststr;
80        domain AgeBRFSS
81                %surveyvar1%
82                ;
83        ods output statistics=stats
84                summary=summary
85                domain=domain ;
86                weight &weight. ;
87        run;
88
89***** TOTALTMP ****************************************************************;
90* Read the totals into memory and create the total row flag variables, trow1   ;
91* flags the total row for cross1 and trow2 flags the total row for cross2.     ;
92* I think the cross2 with ?s is code that ibisq uses to create the program,    ;
93* it checks for cross2 and uses that line in the program only if cross2 exists.;
94* trow1 and trow2 are used in AGEADJUST step and again used in                 ;
95* redflag step,to recode to appropriate values                                 ;
96*******************************************************************************;
97 title2 'TOTALTMP : Stats for total rows (trow1 and trow2 initialized to 1)';
98 data totaltmp;
99        set work.domain;
100        drop DomainLabel VarLabel;
101        /*trow1 and 2 are used later to get aawt*/
102        trow1 = 1;
103        ?cross2? trow2 = 1;
104run;
105 proc print data=totaltmp noobs; run;
106
107***** TMP ********************************************************************;
108* Set domain vars to AgeBRFSS, cross1, cross2 and run survey means            ;
109******************************************************************************;
110 title2 'TMP: SurveyMeans for domain vars and crosses (AgeBRFSS by cross1 and cross2)';
111 proc surveymeans data=tmp nobs sum mean stderr;
112        var &varname.;
113        class &varname.  ;
114        strata ststr;
115        domain AgeBRFSS*%cross1%
116                ?cross2? *%cross2%
117        ;
118        ods output statistics=stats
119                summary=summary
120                domain=domain ;
121                weight &weight. ;
122        run;
123       
124 proc sort data=work.domain;
125        by %cross1% %cross2% AgeBRFSS ;
126        run;
127       
128***** TMPALL *****************************************************************;
129* CONCATENATE TOTAL ROWS ONTO NEW DOMAIN DATASET                              ;
130* work.domain is the new domain output, totaltemp is the new one with the     ;
131* cross1 and cross2 output. (recodes based on var type (char or num)          ;
132* determined use of SAS vtype function                                        ;
133******************************************************************************;
134 title2 'TMPALL: stats for domain vars with totals added';
135 
136 data tmpall;
137        set work.domain totaltmp;
138    &varname.=input(VarLevel, $54.);
139        drop DomainLabel VarLabel;
140       
141        if (vtype(%cross1%)="C" and %cross1%='') then %cross1% = 'tot';
142        if (vtype(%cross1%)="N" and %cross1%=.) then %cross1% = -1;
143        ?cross2? if (vtype(%cross2%)="C" and %cross2%='') then %cross2% = 'tot';
144        ?cross2? if (vtype(%cross2%)="N" and %cross2%=.) then %cross2% = -1;
145       
146        proc print data=tmpall noobs; run;
147
148***** NORMALIZE **************************************************************;
149* Now, go back to work.domain records and compute new weights that are        ;
150* normalized.                                                                 ;
151* What is the problem? Let us say the user filters the dataset to a small     ;
152*  population, like blacks in Kauai, and that population does not have survey ;
153* records in all 7 AA age groups. The weights will not sum to 1.0. So we do   ;
154* this step that finds the age groups that are represented in the filtered    ;
155* dataset, and recomputes (normalizes) the weights so that they sum to 1.0    ;
156* AgeBRFSS - NCHS Statnote20 distribution #9 WITH 75+ FOR HI BRFSS            ;
157******************************************************************************;
158 title2 'NORMALIZE: grab records in work.domain (actual records)';
159 data norm;
160        set work.domain;
161        drop DomainLabel VarLabel;
162        %ageAdjustedFilter%
163        run;
164        proc print data=norm noobs; run;
165
166 title2 'getwts: grab weights for records actually in dataset, row totals denoted when trow1 and trow2 = 1';
167 data getwts;
168        set norm totaltmp;
169       
170    /* this is just to document the age ranges.
171       Age BRFSS is already in the dataset, and is
172                used in the domain statement for aarates.
173                18-24   0.128809768
174                25-34   0.182648111
175                35-44   0.219076679
176                45-54   0.181652285
177                55-64   0.117541734
178                65-74   0.088966942
179                75+     0.081304482
180   */
181
182        aawt=0; /*probably don't need to set these here, but... ??*/
183        if AgeBRFSS="18-24" then aawt=0.128809768;
184        if AgeBRFSS="25-34" then aawt=0.182648111;
185        if AgeBRFSS="35-44" then aawt=0.219076679;
186        if AgeBRFSS="45-54" then aawt=0.181652285;
187        if AgeBRFSS="55-64" then aawt=0.117541734;
188        if AgeBRFSS="65-74" then aawt=0.088966942;
189        if AgeBRFSS="75+"       then aawt=0.081304482;
190       
191        if N=0 then Mean=0;
192
193   run;
194   proc print data=getwts noobs; run;
195
196***** SUMWTS *****************************************************************;
197* PRODUCE THE SUM OF THE WEIGHTS BASED ON THE AGE GROUPS THAT ARE PRESENT     ;
198******************************************************************************;
199 title2 'SUMWTS: sums of the weights for records in dataset by crossvars';
200 proc summary data=getwts nway;
201   var aawt;
202   class %cross1% %cross2% VarLevel;
203   output out=sumwts sum(aawt)=sumwt;
204   proc sort data=sumwts;
205   by %cross1% %cross2% VarLevel;
206   run;
207   proc print data=sumwts noobs; run;
208
209   proc sort data=tmpall;
210   by %cross1% %cross2% VarLevel;
211   run;
212
213***** AGEADJUST **************************************************************;
214* Merge the sum of the weights onto the dataset and divide aawt by sumwt to   ;
215* provide normalized weights.                                                 ;
216* AgeBRFSS - NCHS Statnote20 distribution #9 + 75+, for HI BRFSS              ;
217******************************************************************************;
218 title2 'AGEADJUST: merge sumwts onto dataset, normalize aawts';
219 data AgeAdjust;
220   merge tmpall sumwts;
221   by %cross1% %cross2% VarLevel;
222        aawt=0;
223        if AgeBRFSS="18-24" then aawt=0.128809768;
224        if AgeBRFSS="25-34" then aawt=0.182648111;
225        if AgeBRFSS="35-44" then aawt=0.219076679;
226        if AgeBRFSS="45-54" then aawt=0.181652285;
227        if AgeBRFSS="55-64" then aawt=0.117541734;
228        if AgeBRFSS="65-74" then aawt=0.088966942;
229        if AgeBRFSS="75+"       then aawt=0.081304482;
230   normwt=aawt/sumwt; *normwt is the "normalized" weight for age-adjusting;
231   if trow1=1 then normwt=aawt;
232   if trow2=1 then normwt=aawt;
233   
234   if N=0 then Mean=0;
235
236   run;
237   proc print data=AgeAdjust noobs; run;
238
239***** TMP ********************************************************************;
240* Produce cross-products for weighted percentages.                            ;
241******************************************************************************;
242 title2 'TMP: dataset with cross-products (wgt_percent)';
243 data tmp;
244   set AgeAdjust;
245   keep AgeBRFSS %cross1% %cross2% VarName VarLevel &varname. N Mean StdErr normwt wgt_percent wgt_var trow1 trow2;
246   &varname.=input(VarLevel, $54.);
247   wgt_percent=mean*normwt;
248   wgt_var=stderr*stderr*normwt*normwt; 
249   proc print data=tmp noobs;
250 run;
251
252***** TMP1 *******************************************************************;
253* SUM CROSS-PRODUCTS WITHIN CROSS VARS TO GET AGE-ADJUSTED RATES              ;
254******************************************************************************;
255 title2 'TMP1: age-adjusted, sum of n and weighted percentages and variances';
256 proc summary data=tmp ;
257   var n wgt_percent wgt_var;
258   class  %cross1% %cross2% &varname.;
259   output out=tmp1 sum(n wgt_percent wgt_var)=;
260   run;   
261   proc print data=tmp1 noobs; run;
262   
263***** RATE *******************************************************************;
264* CALCULATE ASYMMETRIC CONFIDENCE INTERVALS                                   ;
265******************************************************************************;
266 title2 'RATE: RATES COMPUTED';
267 data rate;
268   set tmp1;
269
270   stderr=sqrt(wgt_var);
271   f=log(wgt_percent)-log(1-wgt_percent); 
272   s=stderr/(wgt_percent*(1-wgt_percent));
273   Lf=f-1.96*s; 
274   Uf=f+1.96*s; 
275
276   lower=exp(Lf)/(1+exp(Lf));   
277   upper=exp(Uf)/(1+exp(Uf));
278        if %cross1%=. then delete;
279        else if %cross1%='' then delete;
280        ?cross2? if %cross2%=. then delete;
281        ?cross2? else if %cross2%='' then delete;
282    drop f s Lf Uf wgt_var;
283 run;
284 
285  proc sort data=rate;
286   by %cross1%
287   ?cross2? %cross2%
288   &varname.;
289   run;
290
291 proc print data=rate noobs; run;
292
293***** SAMPLEN ****************************************************************;
294* GENERATE UNWEIGHTED SAMPLEN FOR CROSS1, CROSS2 for cell suppression below   ;
295******************************************************************************;
296 title2 'SAMPLEN: the n from all the varname totals';
297 proc summary data=tmpall nway;
298   var N;
299   class %cross1% %cross2%;
300   output out=sampleN sum(N)=sampleN;
301   run;
302 proc sort data=sampleN;
303   by %cross1% 
304   ?cross2? %cross2%
305   ;
306
307   proc print data=sampleN noobs; run;
308
309 title2 'TMP2: SAMPLEN MERGED INTO TMP1 DATA';
310 data tmp2;
311   merge rate sampleN;
312   by %cross1% 
313   ?cross2? %cross2%
314   ;
315   drop _TYPE_ _FREQ_ ;
316   run;
317   proc print data=tmp2 noobs; run;
318
319*****************************************************************;
320********WGTCOUNTS: Add wgtsum field to every record *************;
321***********Used by Hawaii, they want pop num, not samplen********;
322*****************************************************************;
323proc summary data=tmpall nway;  /*need to do proc summary across all AA age groups to get weighted counts*/
324  var Sum;
325  class %cross1%
326  ?cross2? %cross2%
327  &varname.
328  ;
329  output out=wgtcounts sum(Sum)=;
330  proc sort data=wgtcounts; by %cross1%
331  ?cross2? %cross2% &varname.
332  ;
333  proc print; title2 'wgtcounts';
334  run;
335data tmp4; *Add weighted counts field to each record;
336  merge wgtcounts tmp2 ;
337  by %cross1%
338  ?cross2? %cross2%
339  &varname.
340  ;
341  drop _TYPE_ _FREQ_ ;
342  proc print; title2 'tmp4: Add weighted sample field to every record';
343run;
344
345proc summary data=wgtcounts nway;  /*need to do proc summary across all values of indicator to get weighted denominators*/
346        var sum;
347        class %cross1%
348  ?cross2? %cross2%
349  ;
350  output out=weightedN sum(Sum)=wgtsum;
351  proc print; title2 'weightedN';
352  run;
353  proc sort data=weightedN;
354        by %cross1%
355        ?cross2? %cross2%
356        ;
357        run;
358data tmp6; *Add wgtsum field to each record;
359  merge tmp4 weightedN ;
360  by %cross1%
361  ?cross2? %cross2%
362  ;
363  drop _TYPE_ _FREQ_ ;
364  proc print; title2 'tmp6: Add weighted sample denominator to every record';
365run;
366
367**************************************************************************;
368* redflag is the statistical stability indicator, based on                ;
369* the relative standard error (RSE, or coefficient of  variation.         ;
370* recode total rows  to . (char and num) fore ibisq                       ;
371**************************************************************************;
372data rse;
373   set tmp6;
374   
375  if 0<wgt_percent<.50 then RSE=(StdErr/wgt_percent);
376  if .50<=wgt_percent<1 then RSE=(StdErr/(1-wgt_percent));
377 
378  /* %%% Need value attribute in DB for Stable, use VALUE_ATTRIBUTE_NAME value here */
379  redflag=put('BRFSSStable', $14.);
380 /**********************************************************************************************************
381  * Not sure we are using this, just commenting out, and keeping it here;
382  *   If we do use this we will have to change logic way below where we Convert values for cell suppression;
383  *if rse>.3 then redflag=put('Unstable', $14.);
384  *if rse>.5 then redflag=put('VeryUnstable', $14.);
385  ***********************************************************************************************************/
386  /* may want to comment this out at some future date */
387  /* %%% Need value attribute in DB for No Variance, use VALUE_ATTRIBUTE_NAME value here */
388  if wgt_percent in (0 1) then redflag=put('No Variance', $14.);
389 
390        if %cross1%=-1 then %cross1%=.;
391        else if %cross1%='tot' then %cross1%='.';
392        ?cross2? if %cross2%=-1 then %cross2%=.;
393        ?cross2? else if %cross2%='tot' then %cross2%='.';
394       
395  /* Since these are esimates HI wants to round to 100's and sum is weighted numerator */
396 
397   finalsum=ROUND(sum,100);
398   
399   /* had this as  If 0<sum<50 then finalsum=50;, but in reading emails from around 3/18/2019
400    Katherine want this to be if weighted count is less than 50 show 50, because even if no one
401        responded yes to the particular indicator question, that does not mean no one in population, just sample
402  */
403    If sum<50 then finalsum=50;
404   
405   wgtsum=ROUND(wgtsum,100);
406   ageadj_percent=100*wgt_percent;
407   lower=100*lower;
408   upper=100*upper;
409
410   run;
411
412   proc sort data=rate;
413   by %cross1%
414   ?cross2? %cross2%
415   ;
416   run;
417   proc print data=rse noobs; title2 'RSE: RSE computed, totals set to dot'; run;
418
419 ***** Hawaii Small Numbers Rule ************************************;
420 * This is where the cell suppression takes place - will update once ;
421 * Hawaii provides their criteria                                    ;
422 * Suppress cells if unweighted samplesize (SampleN) is less than 50 ;
423 * ZW’s program uses ".A" to identify cells for suppression I have   ;
424 * co-opted his method so I can use the NM/now HI logic for cell     ;
425 * suppression instead of the standard IBIS logic. And I need to use ;
426 * ZWs program because it will suppress the table marginals that can ;
427 * be used to calculate the suppressed cells. Needs                  ;
428 * suppressed_variables code at the end of this file to work.        ;
429 ********************************************************************;
430 title2 'TMP: rate with cell suppression';
431 data tmp;
432        set rse;
433        if &varname = '%spvar2%'; /*This is the value for the indicator dimension passed in by the URL.;*/
434        if (0<SampleN<50) OR  (rse >.3) then do;        /* Hawaii cell supression Rule */
435                ageadj_percent = .A;    * Age-adjustedpercent who answered yes or no;
436                lower = .A;                             * lower confidence interval;
437                upper = .A;                             * upper confidence interval;
438                finalsum = .A;                  * pop estimated weighted numerator;
439                wgtsum = .A;                    * pop estimated weighted denominator;
440  /* %%% Need value attribute in DB for Not Reportable, use VALUE_ATTRIBUTE_NAME value here */
441                redflag=put('BRFSSSuppressed', $16.);
442        end;
443        proc print data=tmp noobs;  title2 'final tmp'; run;
444
445%mend;
Note: See TracBrowser for help on using the repository browser.