1 | #NM_RateAA100K_GE35.def |
---|
2 | #Calculates directly age-adjusted rates per 10,000 for |
---|
3 | # records that have been filtered by IBIS-Q (data=tmp) |
---|
4 | #Uses the IBIS-Q data_frame for cross1 and cross2 |
---|
5 | #Uses an "agepop_frame" so all agegrp18 (agepop elsewhere) |
---|
6 | # groups are always included/represented (weights will sum to 1.0) |
---|
7 | #NM_ in filename = applies cell suppression rule |
---|
8 | #Outputs redflag var based on RSE |
---|
9 | # |
---|
10 | f type special |
---|
11 | ######################################### |
---|
12 | --------BoNdArY-------- |
---|
13 | 1 script |
---|
14 | OPTIONS MPRINT MLOGIC SYMBOLGEN NONUMBER NODATE linesize=175 PAGESIZE=4000; |
---|
15 | OPTION SPOOL; |
---|
16 | |
---|
17 | ************************** 1. TMP ******************************; |
---|
18 | * The dataset 'tmp' is the numerator dataset that has been read ; |
---|
19 | * in already by ibis-q. Any filters have already been applied. ; |
---|
20 | * The proc summary counts deaths by agepop, cross1, and cross2. ; |
---|
21 | * The variable "x" must be in the dataset, it is set equal to 1.; |
---|
22 | ****************************************************************; |
---|
23 | proc summary data=tmp; |
---|
24 | var x; |
---|
25 | class agegrp18 %cross1% |
---|
26 | ?cross2? %cross2% |
---|
27 | ; |
---|
28 | output out=tmp sum=count; |
---|
29 | proc sort data=tmp; by agegrp18 %cross1% |
---|
30 | ?cross2? %cross2% |
---|
31 | ; run; |
---|
32 | proc print data=tmp noobs; |
---|
33 | title1 '---------------------------------'; |
---|
34 | title2 '1. TMP - numerator dataset'; |
---|
35 | run; |
---|
36 | |
---|
37 | ********************** 2. %data_frame% *************************; |
---|
38 | * %data_frame% is a dataset created by IBIS-Q. It consists of ; |
---|
39 | * %cross1% and %cross2% (if the user specified %cross2%) and a ; |
---|
40 | * variable named "count" that has been set to "0". The results ; |
---|
41 | * of the proc summary must be merged with the %data_frame% ; |
---|
42 | * dataset. ; |
---|
43 | ****************************************************************; |
---|
44 | data agepop_frame; |
---|
45 | retain count 0; |
---|
46 | do |
---|
47 | agegrp18 = 1 to 18 by 1 ; |
---|
48 | output; |
---|
49 | end; |
---|
50 | run; |
---|
51 | *************************************************************************************; |
---|
52 | * If user selects specific dimension values, e.g., years, the total dimension value ; |
---|
53 | * will not be included in the data frame. This creates a dimension value for the ; |
---|
54 | * total row. But if user does not select specific values (e.g., selects a year, ; |
---|
55 | * then crosses by sex), there will be a total row for the cross1 and cross2 values. ; |
---|
56 | * So in a later step, the new_frame dataset is sorted with a "nodupkey" option to ; |
---|
57 | * remove the additional dimension total values. ; |
---|
58 | *************************************************************************************; |
---|
59 | data crosstotalframe; |
---|
60 | retain count 0; |
---|
61 | do |
---|
62 | %cross1%=.; |
---|
63 | ?cross2? %cross2%=.; |
---|
64 | output; |
---|
65 | end; |
---|
66 | run; |
---|
67 | data df_%cross1%%cross2%; |
---|
68 | set df_%cross1%%cross2% crosstotalframe; |
---|
69 | run; |
---|
70 | proc print data=df_%cross1%%cross2% noobs; title2 'cross1cross2 frame with total row'; run; |
---|
71 | proc print data=agepop_frame noobs; title2 'agepop frame'; run; |
---|
72 | proc sql; |
---|
73 | create table new_frame as |
---|
74 | select df_%cross1%%cross2%.*, agepop_frame.* |
---|
75 | from df_%cross1%%cross2%, agepop_frame ; |
---|
76 | quit; |
---|
77 | proc sort data=new_frame nodupkey; |
---|
78 | by %cross1% |
---|
79 | ?cross2? %cross2% |
---|
80 | |
---|
81 | agegrp18; |
---|
82 | run; |
---|
83 | proc print data=new_frame noobs; title2 'new_frame, sorted with nodupkey'; run; |
---|
84 | proc sort data=tmp; by %cross1% %cross2% agegrp18; run; |
---|
85 | data newtmp; |
---|
86 | merge new_frame tmp; *must list frame dataset first, then tmp; |
---|
87 | by %cross1% %cross2% agegrp18; |
---|
88 | drop _TYPE_ _FREQ_ ; |
---|
89 | run; |
---|
90 | |
---|
91 | proc print data=newtmp noobs; |
---|
92 | title2 '2. NEWTMP, after frame merged with tmp'; |
---|
93 | run; |
---|
94 | data tmp; |
---|
95 | set newtmp; |
---|
96 | run; |
---|
97 | |
---|
98 | ************************* 3. POP *******************************; |
---|
99 | * Sum the pop counts by age group, cross1 and cross2. ; |
---|
100 | * Read proc summary output, recode the agepop total records, ; |
---|
101 | * cross1 and cross2 totals to -1. ; |
---|
102 | ****************************************************************; |
---|
103 | data poptmp; format agegrp18 %popcross1% %popcross2% 8.; set poptmp; run; |
---|
104 | proc summary data=poptmp; |
---|
105 | var popcount; |
---|
106 | class agegrp18 %popcross1% %popcross2%; |
---|
107 | output out=pop sum=popcount; |
---|
108 | run; |
---|
109 | data pop; |
---|
110 | set pop; |
---|
111 | drop _TYPE_ _FREQ_; |
---|
112 | proc print data=pop noobs; |
---|
113 | title2 '3. POP - denominator dataset'; |
---|
114 | run; |
---|
115 | |
---|
116 | *********************** 4. NUMBERS *****************************; |
---|
117 | * Join tmp, pop. ; |
---|
118 | * -1 values are left of out NUMBERS because stdpop doesn't have ; |
---|
119 | * any -1 values. ; |
---|
120 | ****************************************************************; |
---|
121 | proc sql; |
---|
122 | create table numbers as |
---|
123 | select tmp.*, pop.* |
---|
124 | from tmp left join pop |
---|
125 | on tmp.agegrp18=pop.agegrp18 |
---|
126 | ?popcross1? and tmp.%cross1%=pop.%popcross1% |
---|
127 | ?popcross2? and tmp.%cross2%=pop.%popcross2% |
---|
128 | ; |
---|
129 | quit; |
---|
130 | data numbers; |
---|
131 | set numbers; |
---|
132 | if agegrp18^=.; *get rid of total rows to stop doubling from pop proc summary; |
---|
133 | if %cross1%=. then %cross1%=-1; |
---|
134 | ?cross2? if %cross2%=. then %cross2%=-1; |
---|
135 | proc print data=numbers noobs; |
---|
136 | title2 '4. NUMBERS'; |
---|
137 | title3 ' '; |
---|
138 | run; |
---|
139 | |
---|
140 | ************************ 5. STDWGT *****************************; |
---|
141 | * Select the appropriate records from the stdwgts datafile. ; |
---|
142 | * All weights are for U.S. 2000 standard population (per NCHS ; |
---|
143 | * Statnote20). 'stdvar' values are as follows: ; |
---|
144 | * agepop - the standard 11 age group weights ; |
---|
145 | * agepopGE35 - agepop wgts for age>=35 ; |
---|
146 | * AADist10 - Statnote20 dist #10, for BRFSS ; |
---|
147 | * AADist10GE40 - AADist10 for ages >=40 ; |
---|
148 | * AADist10GE50 - AADist10 for ages >=50 ; |
---|
149 | * AgeGrp18 - 5-year age groups, for cancer data ; |
---|
150 | * AgeGrp18LT50 - AgeGrp18 for age <50 ; |
---|
151 | * AgeGrp18GE50 - AgeGrp18 for age >=50 ; |
---|
152 | * AgeGrp18LT15 - AgeGrp18 for age <15 ; |
---|
153 | * AgeGrp18LT20 - AgeGrp18 for age <20 ; |
---|
154 | ****************************************************************; |
---|
155 | data stdwgt; |
---|
156 | informat stdwgt 7.6; |
---|
157 | set pop.stdwgts; |
---|
158 | *pop libname is set in .cfg file with the saspop statement; |
---|
159 | if (stdvar='AgeGrp18GE25'); *stdvar name is case-sensitive; |
---|
160 | keep agegrp18 stdwgt; |
---|
161 | run; |
---|
162 | proc print data=stdwgt noobs; |
---|
163 | title2 '5. STDWGT- std. pop. weights for direct age-adjustment'; |
---|
164 | run; |
---|
165 | ******************** 6. NUMBERS2 *******************************; |
---|
166 | * Adds the standard population weights to the numerator and ; |
---|
167 | * denominator table. This is done as a separate sql, left join ; |
---|
168 | * to preserve all the -1 values. ; |
---|
169 | ****************************************************************; |
---|
170 | proc sql; |
---|
171 | create table numbers2 as |
---|
172 | select numbers.*, stdwgt.stdwgt |
---|
173 | from numbers left join stdwgt |
---|
174 | on numbers.agegrp18=stdwgt.agegrp18 |
---|
175 | ; |
---|
176 | quit; |
---|
177 | proc print data=numbers2 noobs; |
---|
178 | title2 '6. NUMBERS2- Standard POP wgts merged onto dataset'; |
---|
179 | run; |
---|
180 | |
---|
181 | *********************** 7. AGESPECIFIC *************************; |
---|
182 | * Calculate age-specific rates & cross-products ; |
---|
183 | ****************************************************************; |
---|
184 | data agespecific; |
---|
185 | set numbers2; |
---|
186 | r=(count/popcount); *age-specific proportion; |
---|
187 | ratewgt=r*stdwgt; *weighted age-specific proportion; |
---|
188 | * Montana method... rate_var=count*(stdwgt/popcount)**2; * New formula from doh.wa.gov; |
---|
189 | rate_var=(stdwgt**2)*((r*(1-r))/popcount); |
---|
190 | |
---|
191 | proc print data=agespecific noobs; |
---|
192 | title2 '7. AGESPECIFIC - combines numer and denom data, includes R (age-specific proportion),'; |
---|
193 | title3 'RATEWGT (weighted age-specific rate), and RATE_VAR (rate variance) vars'; |
---|
194 | run; |
---|
195 | |
---|
196 | ************************ 8. AARATE ******************************; |
---|
197 | * Sum the age-specific rates into aa rates, and merge wgtmax. ; |
---|
198 | *****************************************************************; |
---|
199 | proc summary data=agespecific nway; |
---|
200 | var ratewgt rate_var count popcount; |
---|
201 | class %cross1% %cross2%; |
---|
202 | output out=aarate sum(ratewgt rate_var count popcount)=aarate aarate_var count popcount; |
---|
203 | run; |
---|
204 | data aarate; |
---|
205 | set aarate; |
---|
206 | drop _TYPE_ _FREQ_ ; |
---|
207 | run; |
---|
208 | proc sort data=aarate; by %cross1% %cross2%; run; |
---|
209 | proc print data=aarate noobs; |
---|
210 | title2 '8. AARATE - summed across weighted agepop cross-products to get AA rate and'; |
---|
211 | title3 'rate variance within each cross-by var'; |
---|
212 | run; |
---|
213 | |
---|
214 | ******************* 9. TMP *************************************; |
---|
215 | * Almost final IBIS output dataset. ; |
---|
216 | * Make sure no summary rows are included. All -1 totals will be ; |
---|
217 | * coded back to '.' after this step. ; |
---|
218 | ****************************************************************; |
---|
219 | data tmp; |
---|
220 | set aarate; |
---|
221 | if %cross1%=-1 then %cross1%=.; *Recode the statewide totals.; |
---|
222 | ?cross2? if %cross2%=-1 then %cross2%=.; |
---|
223 | |
---|
224 | if (count>0) then do; |
---|
225 | rateper=(aarate*100000); |
---|
226 | rate_se=sqrt(aarate_var); |
---|
227 | stderr=(rate_se*100000); |
---|
228 | end; |
---|
229 | if (count<=0) then do; |
---|
230 | count=0; |
---|
231 | |
---|
232 | rateper=0; |
---|
233 | stderr=sqrt((3/popcount)*(1-(3/popcount))/popcount)*100000; |
---|
234 | end; |
---|
235 | t1=(rateper-(1.96*stderr)); |
---|
236 | if (t1<0) then t1=0; |
---|
237 | LL=put(t1, 8.2); |
---|
238 | UL=put((rateper+(1.96*stderr)), 8.2); |
---|
239 | LL=compress(LL); |
---|
240 | UL=compress(UL); |
---|
241 | n=count; |
---|
242 | |
---|
243 | *********************** 10. Red Flag ****************************; |
---|
244 | * redflag is the statistical stability indicator based on the ; |
---|
245 | * relative standard error (RSE, or coefficient of variation). ; |
---|
246 | * Redflag values created here are converted to images or special ; |
---|
247 | * characters in IBIS-View application XSLTfiles, for instance: ; |
---|
248 | * (xslt\html\query\module\result\ResultPage.xslt, ...Values.xslt ; |
---|
249 | *****************************************************************; |
---|
250 | if count>0 then do; |
---|
251 | rse=(stderr/rateper); |
---|
252 | redflag=put('-', $14.); |
---|
253 | if rse>.3 then redflag=put('Unstable', $14.); |
---|
254 | if rse>.5 then redflag=put('Very Unstable', $14.); |
---|
255 | if stderr=. then redflag=put('Unstable', $14.); |
---|
256 | end; |
---|
257 | if count<=0 then redflag=put('Unstable', $14.); *no variance, n=0, rse=div by zero; |
---|
258 | run; |
---|
259 | |
---|
260 | ************* 11. New Mexico Small Numbers Rule *******************; |
---|
261 | * Suppress cells if the numerator in (1 2 3) AND the denominator ; |
---|
262 | * is less than 20. For Counts, must run the crude rate code to ; |
---|
263 | * capture the denominator, but only output the N. ZW's program ; |
---|
264 | * uses ".A" to identify cells for suppression. I have co-opted ; |
---|
265 | * his method so I can use the NM logic for cell suppression instead; |
---|
266 | * of the standard IBIS logic. And I need to use ZW's program ; |
---|
267 | * because it will suppress the table marginals that can be used to ; |
---|
268 | * calculate the suppressed cells. If this code is used, the .def ; |
---|
269 | * file should have the "NM_" prefix. Needs suppressed_variabes ; |
---|
270 | * code at the end of this file to work. ; |
---|
271 | *******************************************************************; |
---|
272 | data tmp; |
---|
273 | set tmp; |
---|
274 | if ((0<n<4) and (popcount<5000)) then do; |
---|
275 | n = .A; |
---|
276 | rateper = .A; |
---|
277 | LL = put('**', 8.0); |
---|
278 | UL = put('**', 8.0); |
---|
279 | end; |
---|
280 | proc print data=tmp noobs; title2 '11. TMP - final dataset to pass to IBIS View app'; |
---|
281 | run; |
---|
282 | |
---|
283 | --------BoNdArY-------- |
---|
284 | f out_variable |
---|
285 | # definition for output file |
---|
286 | f xml_out_map_file XMLRate100KNDLCLUCL.map |
---|
287 | --------BoNdArY-------- |
---|
288 | f out_detail lbl_not_used__see_xml_out_map_file |
---|
289 | rateper 15.1 |
---|
290 | n 15.0 |
---|
291 | popcount 15.0 |
---|
292 | LL 15.3 |
---|
293 | UL 15.3 |
---|
294 | redflag 15.0 |
---|
295 | --------BoNdArY-------- |
---|
296 | ***************** 12. suppressed variables *************************; |
---|
297 | * ZW's CGI program must be told how many variables it will need to ; |
---|
298 | * suppress and which ones they are. NOTE: If the SAS code, above, is; |
---|
299 | * commented out, these lines can be left in the .def file without ; |
---|
300 | * causing any problems. They will only be used if the SAS code, ; |
---|
301 | * above is active, OR if the small_num and small_pop parameters ; |
---|
302 | * are active in the .CFG file, and with non-zero values. ; |
---|
303 | ********************************************************************; |
---|
304 | --------BoNdArY-------- |
---|
305 | 1 suppressed_variables 2 |
---|
306 | n |
---|
307 | rateper |
---|
308 | --------BoNdArY-------- |
---|