Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
Honghua Chen
1
Program Engine Part 1: Proc Sql copied from sas.com sample proc sql noprint; select trim(left(pgm_name)), count(*) into :_pgms separated by " ", :_count from &module; quit; Part 2: Run all Part 1 + Part 2 = Program Engine
2
Purpose To prove QC has been done To document changes To save time needed for manual checking To catch any minor changes for different versions
3
Basic Ideas Write SAS programs within DATA Steps Output SAS dataset to create SAS programs
4
Example 1 SAS Dataset
5
pgm_code
1 %include "M:\Projects\Company\Drug\Protocol\setup.sas";
2 %macro loadparm; 3 data _null_; 4 pgm_id="ex_drugcomply"; 5 pgm_name="ex_drugcomply1";
6 call symput("_t"||put(1,1.),"Overall compliance with study drug ");
14 call symput("_f"||put(1,1.),"NOTE: Number in parentheses are percentages. ");
20 call symput("_pops","dosed");
Example 1 SAS Dataset cont’d21 call symput("_pgm_id","ex_drugcomply"); 22 call symput("_pgm_name","ex_drugcomply1"); 23 call symput("_total","yes"); 24 call symput("_exe","yes"); 25 call symput("_portrait","LANDSCAPE"); 26 call symput("_sigdig","5.2"); 27 run; 28 %mend loadparm; 29 %loadparm;
6
Example 1 SAS program %include "O:\Company\Drug\Protocol\setup.sas"; %macro loadparm; data _null_; pgm_id="ex_drugcomply"; pgm_name="ex_drugcomply1"; call symput("_t"||put(1,1.),"Overall drug compliance"); call symput("_f"||put(1,1.),"NOTE: Number in parentheses are percentages. ");
call symput("_f"||put(2,1.),""); …
7
Example 1 SAS program cont’d call symput("_pops","dosed"); call symput("_pgm_id","ex_drugcomply"); call symput("_pgm_name","ex_drugcomply1"); call symput("_total","yes"); call symput("_exe","yes"); call symput("_portrait","LANDSCAPE"); call symput("_sigdig","5.2"); run; %mend loadparm; %loadparm;
8
Example 2 SAS program data qc_ods_rtf; length pgm_code $200; pgm_code='open (INFILE,"'||"&in_folder"||'/'||"&pgm_name"|| '.sas" ) or die "can not open the input file";'; output; pgm_code='open (OUTFILE,">'||"&out_folder"||'/'||"&pgm_name"|| '‐temp.sas" ) or die "can not open output file";'; output; pgm_code='select (OUTFILE);'; output; pgm_code='while (<INFILE>){'; output;
9
Example 2 SAS program cont’d pgm_code='s/'||"&s_string"||'/ods listing close; options nodate
nonumber'|| ' ORIENTATION=LANDSCAPE device=SASEMF; '; output; pgm_code='ods rtf file="&out_folderx.'|| '&slashx.'||"&pgm_name"||'‐temp.rtf";/g;'; output; pgm_code='s/'||"&e_string"||'/ods rtf close; ods listing; /g;'; output; pgm_code='print; }'; output; pgm_code='close (INFILE);'; output; pgm_code='close (OUTFILE);'; output; run;
10
Create a SAS program %macro putpgm(pgmname); filename autopgm "&out_folder./&pgmname..sas"; run; data _null_; file autopgm; set &pgmname; *** Calculate length for the program code indentation ***; l1=length(pgm_code); l2=length(trim(left(pgm_code))); l=l1‐l2; if l > 0 then
11
Create a SAS program cont’d ***@|@@ are called trailing @ and double trailing @. Use an @ or @@ to hold the pointer at its current location. The next
PUT statement that executes writes to the same output line rather than to a new output line.;
do i = 1 to l; put " " @@; end; put pgm_code; run; %mend putpgm; *** Call program writing utility macro putpgm to write out perl or sed program qc_ods_rtf.sas ***; %putpgm(qc_ods_rtf);
12
Example 2
13
pgm_code1 open (INFILE,"&in_folder/&pgm_name.sas" ) or die "can not open the input file";
2 open (OUTFILE,">&out_folder/&pgm_name‐temp.sas" ) or die "can not open output file";
3 select (OUTFILE); 4 while (<INFILE>){
5 s/&s_string/ods listing close; options nodate nonumberORIENTATION=LANDSCAPE device=SASEMF;
6 ods rtf file="&out_folderx.&slashx.&pgm_name‐temp.rtf";/g;
7 s/&e_string/ods rtf close; ods listing; /g;
8 print; } 9 close (INFILE); 10 close (OUTFILE);
Example 2 Perl program open (INFILE,"/company/drug/protocol/l‐ae‐complst.sas" ) or die "can
not open the input file"; open (OUTFILE,">/company/drug/protocol/l‐ae‐complst‐temp.sas" )
or die "can not open output file"; select (OUTFILE); while (<INFILE>){ s/%prtsetup;/ods listing close; options nodate nonumber
ORIENTATION=LANDSCAPE device=SASEMF; ods rtf file="&out_folderx.&slashx.l‐ae‐complst‐temp.rtf";/g; s/%pageprt;/ods rtf close; ods listing; /g; print; } close (INFILE); close (OUTFILE);
14
Required Parameters %get_final(in_folder=%str(M:\company\drugname\protocols), out_folder=%str(M:\company\drugname\protocols),
pgm_name=l‐dm, s_string=%nrstr(%prtsetup;), e_string=%nrstr(%pageprt;),debug=yes);
15
Primary Final
16
col1 col2 col3 col4 col5 col6 col7 col8
1 200‐002 2/2/1983 29 FEMALE ASIAN NOT HISPANIC OR LATINO 193.3 94
2 300‐003 3/3/1964 48 MALE WHITE NOT HISPANIC OR LATINO 190 91
3 400‐004 4/4/1975 37 FEMALE BLACK OR AFRICAN AMERICAN
NOT HISPANIC OR LATINO 186.7 88
4 500‐005 5/5/1985 27 MALE WHITE NOT HISPANIC OR LATINO 183.3 84
5 600‐006 6/6/1980 32 FEMALE WHITE NOT HISPANIC OR LATINO 180 81
6 700‐007 7/7/1954 58 MALE BLACK OR AFRICAN AMERICAN
NOT HISPANIC OR LATINO 176.7 78
7 800‐008 8/8/1988 23 FEMALE WHITE NOT HISPANIC OR LATINO 173.3 75
8 900‐009 9/9/1990 22 MALE WHITE NOT HISPANIC OR LATINO 170 72
Primary TIT COLHD FT
17
text group
1 The SAS System 1004
2 Listing of demographics and baseline characteristics 1008
3 Full Analysis Set 10124 N=8 10165 ‐‐ 20036 Subject ID 20147 Birth Date 20158 Age (years) 20169 Sex 201710 Race 201811 Ethnicity 201912 Height (cm) 202013 Weight (kg) 2021
14 NESUG NESUG NESUG NESUG NESUG NESUG NESUG NESUG NESUG NESUG 3004
Proc compare instead of eyeballing the data proc compare data=primary_tit_colhd_ftcomp=qc_tit_colhd_ft listall; run;
proc compare data=primary_final comp=qc_finallistall; run;
18
Macro for both Win and UNIX %if (&sysscp = WIN) %then %do;
%end;
%else %do;
%end;
19
SED Script s/%prtsetup;/ods listing close; options nodate nonumberORIENTATION=LANDSCAPE device=SASEMF; ods rtf file="\&out_folderx.\&slashx.l‐dm‐temp.rtf";/g;
s/%pageprt;/ods rtf close; ods listing; /g;
20
Run SED script ***** SED setup can be downloaded from gnuwin32.sourceforge.net/packages/sed.htm *****;
*** Run SED program with paramater qc_ods_rft.sas to create a modified primary program &pgm_name.‐temp.sas ***;
option NOXWAIT; X "cd &out_folder\"; X "start /b C:\Hua\GnuWin32\bin\sed ‐f qc_ods_rtf.sas&pgm_name..sas > &pgm_name.‐temp.sas";
21
Run modified program *** Execute the modified primary program &pgm_name.‐temp.sas ***;
%include "&out_folder./&pgm_name.‐temp2.sas";
22
RTF Title FootnoteThe SAS System
Listing of demographics and baseline characteristics
Full Analysis Set
N=8
23
NESUG NESUG NESUG NESUG NESUG NESUG NESUG NESUG NESUGNESUG
M:\Company\Drug\Protocol\l‐dm.sas 14NOV2012
RTF Table
Subject ID Birth Date
Age(years) Sex Race Ethnicity
Height(cm)
Weight(kg)
200‐002 1983‐02‐02 29 FEMALE ASIAN NOT HISPANIC OR LATINO 193.3 93.8
300‐003 1964‐03‐03 48 MALE WHITE NOT HISPANIC OR LATINO 190.0 90.7
400‐004 1975‐04‐04 37 FEMALE BLACK OR AFRICAN AMERICAN NOT HISPANIC OR LATINO 186.7 87.6
500‐005 1985‐05‐05 27 MALE WHITE NOT HISPANIC OR LATINO 183.3 84.4
600‐006 1980‐06‐06 32 FEMALE WHITE NOT HISPANIC OR LATINO 180.0 81.3
700‐007 1954‐07‐07 58 MALE BLACK OR AFRICAN AMERICAN NOT HISPANIC OR LATINO 176.7 78.2
800‐008 1988‐08‐08 23 FEMALE WHITE NOT HISPANIC OR LATINO 173.3 75.1
900‐009 1990‐09‐09 22 ‐‐ WHITE NOT HISPANIC OR LATINO 170.0 72.0
24
Read in the RTF File data rtf_input; infile "&out_folder./&pgm_name.‐temp.rtf" delimiter='00'x MISSOVER DSD lrecl=32767 firstobs=1; format f1 $500.; input f1 $ ; run;
25
RTF Tags
f1 text
\pard\plain\intbl\sb60\sa60\ql\f1\fs20\cf1{200‐002\cell} 200‐002
\pard\plain\intbl\sb60\sa60\ql\f1\fs20\cf1{1983‐02‐02\cell}
1983‐02‐02
\pard\plain\intbl\sb60\sa60\qr\f1\fs20\cf1{29\cell} 29
\pard\plain\intbl\sb60\sa60\ql\f1\fs20\cf1{FEMALE\cell} FEMALE
\pard\plain\intbl\sb60\sa60\ql\f1\fs20\cf1{ASIAN\cell} ASIAN
\pard\plain\intbl\sb60\sa60\ql\f1\fs20\cf1{NOT HISPANIC OR LATINO\cell}
NOT HISPANIC OR LATINO
\pard\plain\intbl\sb60\sa60\ql\f1\fs20\cf1{193.3\cell} 193.3
\pard\plain\intbl\sb60\sa60\ql\f1\fs20\cf1{93.8\cell} 93.8
26
RTF Pocket Guide [2] Sean M. Burke “The Universal Document Format RTF Pocket Guide”
27
QC program example proc sort data=crtdir.adae out=adae_01; by armcd subjid aestdy aestdt aesttm aeterm aedecod; run;
data adae_02; set adae_01(keep=armcd armlbl subjid aestdy aestdt aesttm aeendy duration
aestdtc aeendtc aeseq aeout aecontrt aeacn aewd aeser aeterm
aedecod aesev aerel aesern aerefid dosedfn); by armcd subjid aestdy aestdt aesttm aeterm aedecod; where dosedfn = 1 and aeterm ^= ''; proc sort; by subjid aestdtc aeendtc aedecod aeseq ; run;
28
QC program example cont’d data adae_03; set adae_02; by subjid; if not first.subjid then subjid = '';
run;
proc sql; select count(*) into :obsnum from adae_02; quit;
29
QC program example cont’d data adae_03; set adae_02; by subjid; if not first.subjid then subjid = '';
run;
proc sql; select count(*) into :obsnum from adae_02; quit;
30
QC program example cont’d %include "/company/drug/protocol/get_final.sas";
%get_final(in_folder=%str(/company/drug/protocol//prog/), out_folder=%str(//company/drug/protocol//qc/), pgm_name=l‐ae‐lst, s_string=%nrstr(%prtsetup;), e_string=%nrstr(%pageprt;),debug=no);
31
QC program example cont’d data qc_final; set adae_03; length col1 ‐ col11 $1000; keep col1 ‐ col11; col2 = aedecod; if aestdy ^= . then col3 = trim(left(put(aestdy,best.))); if aeout='NOT RESOLVED' then col4 = 'NR'; else if aeendy ^= . then col4 = trim(left(put(aeendy,best.))); else col4 = 'XX'; col5 = trim(left(put(duration,best.)));
32
QC program example cont’d col6 = aesev; col7 = aecontrt; if aeacn = 'DRUG WITHDRAWN' then col8='DW'; else if aeacn = 'DOSE INTERRUPTED' then col8='DInt'; else if aeacn = 'DOSE REDUCED' then col8='DR'; else if aeacn = 'DOSE INCREASED' then col8='DInc'; else col8 = aeacn; col9 = aerel; if aewd=1 then col10='Y'; else if aewd=0 then col10='N'; col11 = aeser; run;
33
QC program example cont’d data qc_tit_colhd_ft; length text $1000; text = 'Adverse events ‐ subject listing'; output; text = 'Treatment group: Annual Report'; output; text = '#PAGE'; output; text = 'Study day __'; output; text = 'Subject number'; output; text = 'MedDRA Preferred term'; output; text = 'Onset'; output; text = 'Res'; output; text = 'Durat‐ ion (days)'; output;
34
QC program example cont’d text = 'Severity'; output; text = 'Concom‐ itant treat given'; output; text = 'Action taken with study drug'; output; text = 'Relation‐ ship to study drug'; output; text = 'Resulted in withdrawal from study'; output; text = 'Serious'; output; text = 'NOTE: *=Onset prior to first dose.'; output; text = 'Abbreviations: DW=Drug withdrawn; NR=Not
resolved; Res=Resolved; treat=Treatment; Y=Yes; N=No.'; output; *text = 'DInt=Dose interupted; *DR=Dose reduced;
*DInc=Dose increased.'; *output; run;
35
QC program example cont’d
proc compare data=primary_tit_colhd_ftcomp=qc_tit_colhd_ft listall; run;
proc compare data=primary_final comp=qc_final listall; run;
36
Another QC macro * Product: general * Protocol: general * Project: general * Program name: compare_lst * Developer/Programmer: Honghua Chen * Date: * Purpose: Compare all lst files in prog and qc folders * Platform: HP‐UX * SAS Version: 9.2 * * Modifications: *
37
BioStarted out as DBA 25 years ago (8 years clinical trial SAS® software experience)
[email protected]@ockham.comTel: 443‐938‐0592
38