three step table validation pharmasug 2007
DESCRIPTION
I wrote this when I joined Forest in 2006. It extracts the main body of Table and compares it with the validator\'s output. It can pinpoint the differences and is extremely efficient and accurate. Valuable tool for large table validation. Presented at Pharmasug 2007, DenverTRANSCRIPT
Drawback of Manual Validation
• Low efficiency & time consuming.
• Easy to miss.• Hard to archive.
Try our 3-step Validation!
You only need:
• %TBLSTR• %ANYTL (%DATASTR will retire)
• %COMPSTR
Step 1: TBLSTR
Function:
1. Locate the target table
2. Convert table content into a dataset
Usage:
%TBLSTR(Table Name)
Find the table file! There are 2 lst files in the user output area for Table 14.5.6.1 However, only the latest produced lst file will be used for comparision
1 shu t14_561.lst /sasprog/xyz/xyzmd01/shu/output/tables/t14_561.lst 08AUG06:14:00:00 1 Table 14.5.6.1 Table 14.5.6.1 2 nberg t14050601.lst /sasprog/xyz/xyzmd01/nberg/output/tables/t14050601.lst 29NOV06:15:32:00 1 Table 14.5.6.1 Table 14.5.6.1
%TBLSTR(Table 14.5.6.1)
Example:
Forest Research Institute Protocol XYZ-MD-01 Page 1 of 2
Table 14.5.6.1 ECG Table by Treatment of Drug XYZ Safety Population _________________________________________________________________________________________________________________________ XYZ _________________________________________________________________________________________ Placebo A B C D ECG Parameter (Unit) (N=16) (N=6) (N=6) (N=6) (N=5) PCS Criterion n/N1 (%) n/N1 (%) n/N1 (%) n/N1 (%) n/N1 (%) _________________________________________________________________________________________________________________________PR Interval (msec) >= 250 0/16 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/5 (0.0) QRS Interval (msec) >= 150 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) QTcB Interval (msec) > 500 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) QTcF Interval (msec) > 500 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) QTcI Interval (msec) > 500 0/16 (0.0) 0/6 (0.0) 1/6 (16.7) 0/6 (0.0) 0/5 (0.0) _________________________________________________________________________________________________________________________Notes: PCS = Potentially clinically significant. N1 = Number of patients with available non-PCS baseline and at least one post-baseline assessment. n = Number of patients (of the N1 patients) who met the criterion at least once during Double-Blind Period. Report generated by program: /sasprog/xyz/xyzmd01/nberg/programs/tables/t14050601.sas Draft 11/29/2006 15:32
___________________________________________________________
____________________________________________________________
Report generated by program
Then convert it into a dataset Obs LN 1 PR Interval (msec) 2 >= 250 0/16 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/5 (0.0) 3 QRS Interval (msec) 4 >= 150 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 5 QTcB Interval (msec) 6 > 500 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 7 QTcF Interval (msec) 8 > 500 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 9 QTcI Interval (msec) 10 > 500 0/16 (0.0) 0/6 (0.0) 1/6 (16.7) 0/6 (0.0) 0/5 (0.0) 11 PR Interval (msec) 12 >= 250 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/45 (0.0) 0/61 (0.0) 13 QRS Interval (msec) 14 >= 150 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0) 15 QTcB Interval (msec) 16 > 500 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0) 17 QTcF Interval (msec) 18 > 500 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0) 19 QTcI Interval (msec) 20 > 500 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 1/46 (2.2) 1/62 (1.6)
INTERLEAVE
More than one-page table?
Solution: ‘stitch’ them back.
Example %TBLSTR(Table 14.5.6.1, page= 2, idsize=30)
PR Interval (msec)
>=250
QRS Interval (msec)
>=150
QTcB Interval (msec)
>500
QTcF Interval (msec)
>500
QTcI Interval (msec)
>500
Forest Research Institute Protocol XYZ-MD-01 Page 2 of 2
Table 14.5.6.1
ECG Table
Safety Population
______________________________________________________________________________________________________________
XYZ
___________________________________________________________________
E F G H All XYZ Total
ECG Parameter (Unit) (N=6) (N=6) (N=6) (N=6) (N=46) (N=62)
PCS Criterion n/N1 (%) n/N1 (%) n/N1 (%) n/N1 (%) n/N1 (%) n/N1 (%)
______________________________________________________________________________________________________________
______________________________________________________________________________________________________________
Notes: .
Report generated by program: /sasprog/xyz/xyzmd01/nberg/programs/tables/t14050601.sas Draft 11/29/2006 15:32
%TBLSTR(Table 14.5.6.1,
page= 2,
idsize=30)
Forest Research Institute Protocol XYZ-MD-01 Page 1 of 2
Table 14.5.6.1 ECG Table Safety Population __________________________________________________________________________________ XYZ ___________________________________________________ Placebo A B C D ECG Parameter (Unit) (N=16) (N=6) (N=6) (N=6) (N=5) PCS Criterion n/N1 (%) n/N1 (%) n/N1 (%) n/N1 (%) n/N1 (%) __________________________________________________________________________________PR Interval (msec) >= 250 0/16 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/5 (0.0) QRS Interval (msec) >= 150 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) QTcB Interval (msec) > 500 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) QTcF Interval (msec) > 500 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) QTcI Interval (msec) > 500 0/16 (0.0) 0/6 (0.0) 1/6 (16.7) 0/6 (0.0) 0/5 (0.0) __________________________________________________________________________________Notes: Report generated by program: /sasprog/xyz/xyzmd01/nberg/programs/tables/t14050601.sas
Draft 11/29/2006 15:32
0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/45 (0.0) 0/61 (0.0)
0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0)
0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0)
0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0)
0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 1/46 (2.2) 1/62 (1.6)
30
page= 2
idsize=30
Convert it to a dataset _TBLSTR Obs _TBLSTR
1 PR Interval (msec)
2 >= 250 0/16 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/45 (0.0) 0/61 (0.0)
3 QRS Interval (msec)
4 >= 150 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0)
5 QTcB Interval (msec)
6 > 500 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0)
7 QTcF Interval (msec)
8 > 500 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0)
9 QTcI Interval (msec)
10 > 500 0/16 (0.0) 0/6 (0.0) 1/6 (16.7) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 1/46 (2.2) 1/62 (1.6)
Protocol WZY-MD-01 Page 1 of 8 Table 14.5.6.2 List of ECG Safety Population ______________________________________________________________________________________________________Paramter PCS Treatment Age/Sex Time Visit Date (unit) Criteria Patient ID Period Race /# Visit (Day) Value _____________________________________________________________________________________________________ PR Interval >= 250 0010020 Screening 34/M/ 0.0 / 1 DAY -1 08/05/2005 214 (msec) White (0) 0.0 / 2 DAY -1 08/05/2005 232 (0) ______________________________________________________________________________________________________Protocol WZY-MD-01 Page 2 of 8 Table 14.5.6.2 List of ECG Safety Population ______________________________________________________________________________________________________Paramter PCS Treatment Age/Sex Time Visit Date (unit) Criteria Patient ID Period Race /# Visit (Day) Value _____________________________________________________________________________________________________ PR Interval >= 250 0010020 Screening 34/M 5.0 / 1 DAY -1 08/05/2005 220(msec) White (0) 5.0 / 2 DAY -1 08/05/2005 243 (0)
Remove repeated columns in Listing
11 7207 5
Call %RMGRP( ) after %TBLSTR to remove the repeated ID columns
11 7 20 7 5
New feature: %TBLSTR(Table xx, type=list) or title contains ‘Listing’, it will automatically determine ID column width. Try it and give me feedback.
Step 2: DATASTR
Purpose: Concatenate column variables into one
with wrapping and indentationUsage:
%_ANYTL(, dataname.variable list, Table xx)
or %DATASTR(dataname.variable list) **outdated
Example
Suppose we have a dataset called _final
It has 11 variables: Obs CL1 CL2 CL3 CL4 CL5 CL6 CL7 CL8 CL9 CL10 CL11
1 0/16(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/39(0.0) 0/61(0.0)
2 0/16(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/40(0.0) 0/62(0.0)
3 0/16(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/40(0.0) 0/62(0.0)
4 0/16(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/40(0.0) 0/62(0.0)
5 0/16(0.0) 0/6(0.0) 1/6(16.7) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 1/40(2.5) 1/62(1.6)
%anytl( ,
_final.cl1 cl2 cl3 cl4 cl5 cl6 cl7 cl8 cl9 cl10 cl11,
Table 14.5.6.2)
Obs _DATASTR 1 0/16(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/39(0.0) 0/61(0.0) 2 0/16(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/40(0.0) 0/62(0.0) 3 0/16(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/40(0.0) 0/62(0.0) 4 0/16(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/40(0.0) 0/62(0.0) 5 0/16(0.0) 0/6(0.0) 1/6(16.7) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 1/40(2.5) 1/62(1.6)
Listing type table
1. Group variables
2. Long variable
Protocol WZY-MD-01 Page 1 of 8
Table 14.5.6.2
List of ECG
Safety Population
______________________________________________________________________________________________________
PCS Treatment Cohort/ Time Visit Date
ECG Parameter (Unit) Criteria Group Patient ID Period Age/Sex /Replicate # Visit (Day) Value
_____________________________________________________________________________________________________
PR Interval (msec) >= 250 XYZ/ B/0010020 Screening 34/M 0.0 / 1 DAY -1 08/05/2005 214
(0)
0.0 / 2 DAY -1 08/05/2005 232
(0)
_final has repeat values%ANYTL (, _final . param pcshigh treatc pidc period agesex/or timerep visit visday/10 valpcs, Table 14.5.6.2)
Obs PARAM PCSHIGH TREATC PIDC PERIOD AGESEX TIMEREP VISIT VISDAY VALPCS 1 PR Interval (msec) >= 250 XYZ/ B/0010020 Screening 34/M 0.0/1 DAY -1 08/05/2005 214
OR : /order order=data
10
2 PR Interval (msec) >= 250 XYZ/ B/0010020 Screening 34/M 0.0/2 DAY -1 08/05/2005 232 ….
(0)
(0)
Now we get dataset _DATASTR as Obs _DATASTR 1 PR Interval (msec) >= 250 XYZ/ B/0010020 Screening 34/M 0.0/1 DAY -1 08/05/2005 214 2 (0) 3 0.0/2 DAY -1 08/05/2005 232 4 (0)
Step3: COMPSTR
From validation dataset, we generates another dataset _datastr by using %ANYTL/%DATASTR: Obs _DATASTR 1 0/16(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/39(0.0) 0/61(0.0) 2 0/16(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/40(0.0) 0/62(0.0) 3 0/16(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/40(0.0) 0/62(0.0) 4 0/16(0.0) 0/6(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/40(0.0) 0/62(0.0) 5 0/16(0.0) 0/6(0.0) 1/6(16.7) 0/6(0.0) 0/5(0.0) 0/6(0.0) 0/6(0.0) 0/5(0.0) 0/6(0.0) 1/40(2.5) 1/62(1.6)
From primary Table 14.5.6.1 we generates a dataset _tblstr by using %TBLSTR Obs _TBLSTR
1 PR Interval (msec) 2 >= 250 0/16 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/45 (0.0) 0/61 (0.0) 3 QRS Interval (msec) 4 >= 150 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0) 5 QTcB Interval (msec) 6 > 500 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0) 7 QTcF Interval (msec) 8 > 500 0/16 (0.0) 0/6 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/46 (0.0) 0/62 (0.0) 9 QTcI Interval (msec) 10 > 500 0/16 (0.0) 0/6 (0.0) 1/6 (16.7) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 0/6 (0.0) 0/5 (0.0) 0/6 (0.0) 1/46 (2.2) 1/62 (1.6)
Different in structure!?
Give them some massage, but be careful!For example: DATA _TBLSTR; SET _TBLSTR; IF substr(_tblstr, 30) = ' ' THEN DELETE; _tblstr = substr(_tblstr, 6);RUN;
Now we are ready!
%COMPSTR
The difference 14:36 Wednesday, December 13, 2006 3
----------------------------------------------------------------------------- Page 1 --------------------------------------------------------------Line source _compstr
1 Programmer 0/16(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/45(0.0)0/61(0.0)
1 Validator 0/16(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/39(0.0)0/61(0.0)
1 Differences ................................................................................................... ................XX...................
2 Programmer 0/16(0.0)0/6(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/46(0.0)0/62(0.0)
2 Validator 0/16(0.0)0/6(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/40(0.0)0/62(0.0)
2 Differences .....................................................................................................................X......................
3 Programmer 0/16(0.0)0/6(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/46(0.0)0/62(0.0)
3 Validator 0/16(0.0)0/6(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/40(0.0)0/62(0.0)
3 Differences .....................................................................................................................X.....................
4 Programmer 0/16(0.0)0/6(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/46(0.0)0/62(0.0)
4 Validator 0/16(0.0)0/6(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/40(0.0)0/62(0.0)
4 Differences .....................................................................................................................X....................
5 Programmer 0/16(0.0)0/6(0.0)1/6(16.7)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)1/46(2.2)1/62(1.6)
5 Validator 0/16(0.0)0/6(0.0)1/6(16.7)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)1/40(2.5)1/62(1.6)
5 Differences .......................................................................................................................X...X................
We are not matching!
Line source _COMPSTR 1 Prog/Vali 0/16(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/45(0.0)0/61(0.0) 2 Prog/Vali 0/16(0.0)0/6(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/46(0.0)0/62(0.0) • Prog/Vali 0/16(0.0)0/6(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/46(0.0)0/62(0.0) • Prog/Vali 0/16(0.0)0/6(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)0/46(0.0)0/62(0.0) • Prog/Vali 0/16(0.0)0/6(0.0)1/6(16.7)0/6(0.0)0/5(0.0)0/6(0.0)0/6(0.0)0/5(0.0)0/6(0.0)1/46(2.2)1/62(1.6)
Fix the problem, see what happens
There is no difference between Validator and Programmer. It is fully validated
Meanwhile: Automatic Summary
/sasprog/drug/study/programs/HDFT.txt
Summary
• Easy
• Fast
• Accurate• Flexible