Any Tl A Versatile Tablelisting Macro Forest Pharmasug 2009

Preview:

Citation preview

Traditional Table Macro

• Many macros for different table types

• Numerous parameters.

• Hard to remember and customize

Demographic

Validation

AE, CONMED, MEDHIS, shift…

Various Efficacy

Various Efficacy VITAL, ECG …

LAB….

Demographic…

Listing

Features of %anyTL

• 1 macro with only 3 parameters

• special characters as operators

• can be modified with data step

• add titles/footnotes, big N, adjust column widths, wrap/indent text, paginate, validation… AUTOMATICALLY!

Background 1: The 3 dimensions of a table:%anyTL(row_define, column_define, table_num);

Background 2: Three types of data and basic grammar

PROF.age

Calculate N, SD, Mean, Min, Max and Median of the continuous variable age from PROF dataset.

Calculate the percentage: = number of records in each category of the categorical variable sex from PROF dataset divided by number of records from PROF dataset where safety=1.

PROF.sex/PROF.safety@1 PROF.sex/PROF.safety(=1)

‘This is a text ’ This is a text

Quotation ‘ or “ mark to indicate Text.

safety@1safety(=1)

PART I

Basic Tables

%anyTL( PROF.age‘ Age (years)’ PROF.sex‘ Sex, n(%)’/safety@1,

treat+ total,

Table 1);

(1)Basic Demographic Type Tables

PROF.PROF.age

sex safety@1/‘ Age (years)’ ‘ Sex, n(%)’

%anyTL( LAB.test*visit*value,

treat,

Table 2)

(2) * Hierarchical Tables

LAB.test visit value

Table 2Lab Result by Test and Visit

Safety Population

%anyTL( AE. socterm**prefterm/PROF.safety@1#, treat**severity, Table 3)

(3) * * AE Tables

• #: number of subjects(unique SPID, the only standard variable required), otherwise number of records

PROF.AE. socterm prefterm

• treat**severity: only count the severest at each level for each patient• treat*sex: count by subcategory

• **: produce counts for EVERY class level• *: produce counts for only the lowest class level

/ #

Table 3AE by System Organ Class and Preferred Term

Safety Population

%anyTL( AE. aeterm1** aeterm2** aeterm3**aeterm4/PROF.safety@1#, treat*sex**related,

Table 4)

(3) * * AE Tables (Multiple aeterms and Multiple column levels)

Term 1 / Term 2/ Term 3/ Term 4

Treatment A Treatment B

Male(N=XXX)

Female(N=XXX)

Male(N=XXX)

Female(N=XXX)  

Unrelatedn (%)

Relatedn (%)

Unrelatedn (%)

Relatedn (%)

Unrelatedn (%)

Relatedn (%)

Unrelatedn (%)

Relatedn (%)

AE TERM 1 xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x)

AE TERM 2 xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x)

AE TERM 3 xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x)

AE TERM 4 xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x)

AE TERM 4 xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x) xx (xx.x)

PART II

Advanced Tables(other symbols)

(1) /, //, /// display format for categorical variables

%anyTL( PE.visit*peterm/ ? ,

treat,

Table 5 )

• var/1 -> x

• var1/var2 -> x (%)

• var1//var2 -> x/xxx

• var1///var2 -> x/xxx (%)

PE.visit*peterm/1, PE.visit*peterm/visit*safety@1, PE.visit*peterm//visit*safety@1, PE.visit*peterm///visit*safety@1,

?

?

?

?

%anyTL( mylib.d_ecg(WHERE=(safety=1)).anvis*bsrslt/anvis*safety@1#,

treat*result,

Table 6)

(2) Denominator by visit (eg. Shift Table)

Treatment A Treatment B

mylib.d_ecg(WHERE=(safety=1)).

• class1*class2*…*var1/class1*class2*…var2(=value)

Population Clinical Response

Treatment A(N=XXX)

Treatment B(N=XXX)

ITT Population

N xx xx

Clinical Cure xx (xx.x) xx (xx.x)

Clinical Failure xx (xx.x) xx (xx.x)

Indeterminate xx (xx.x) xx (xx.x)

• By default, all categories in the cateogrical var.’s format will be displayed

(3) = Select Range

%anyTL(PROF(WHERE=(itt=1)). (‘ITT Population’ itt‘ N’@1/1 clinrsp‘’/itt@1#),treat, Table 8)

%anyTL(PROF(WHERE=(itt=1)). (‘ITT Population (EXCLUDE INDETERMINATE)’ itt‘ N’@1/1 clinrsp‘’@1@2/safety@1#) ,

• @val1@val2 : in (val1, val2). Use @‘val1’@‘val2’ for character variable

%anyTL(PROF(WHERE=(itt=1)). (‘ITT Population (EXCLUDE INDETERMINATE)’ itt‘ N’@1/1 clinrsp‘’^@3/safety@1#) ,

• ^@val1 : not in (val1)

(4) ( Group Variables )

%anyTL( PROF. ( ‘Race, n (%)’ white‘ White’@1/safety@1 indian‘ US. Indian’@1/safety@1 asian‘ Asian’@1/safety@1),

treat,

Table 7)

• The variables within ( ) will be treated as one block, no blank line

Demographic Parameter

Treatment A(N=XXX)

Treatment B(N=XXX)

Race, n (%)

White xx (xx.x) xx (xx.x)

US. Indian xx (xx.x) xx (xx.x)

Asian xx (xx.x) xx (xx.x)

%anyTL( PROF. ( ‘Race, n (%)’ white ‘ White’ indian ‘ US. Indian’ asian ‘ Asian’)@1/safety@1,

treat,

Table 7)

• The Information outside ( ) is shared

whiteindian

asian

‘Race, n (%)’‘ White’

‘ US. Indian’‘ Asian’

(5) + ‘Plug-in’ Statistical Model %anyTL(PROF(WHERE=(itt=1)). (‘ITT Population’ itt‘ N’@1/1 clinrsp‘’/itt@1#), treat, Table 9)

• A statistical analysis library available: +SEM, +logistic +fisher, +anova, +ancova[covariable] ….

• Build new plug-in statistical model, following template

Population Clinical Response

Treatment A(N=XXX)

Treatment B(N=XXX)

ITT Population

N xx xx

Clinical Cure xx (xx.x) xx (xx.x)

Clinical Failure xx (xx.x) xx (xx.x)

Indeterminate xx (xx.x) xx (xx.x)

%anyTL(PROF(WHERE=(itt=1)). (‘ITT Population’ itt‘ N’@1/1 clinrsp‘’/itt@1#+CMH), treat, Table 9 )

P-Value

x.xx

%anyTL( VITAL.visit*bslval|value|change,

treat,

Table 10 )

(6) | Parallel | Summaries |

Visit/ Statistics

Treatment A(N=xxx)

Treatment B(N=xxx)

Baseline Value Change Baseline Value Change

Visit 1

Mean xx.x xx.x xx.x xx.x xx.x xx.x

SD xx.x xx.x xx.x xx.x xx.x xx.x

Median xx.X xx.X xx.X xx.X xx.X xx.X

Min,Max xx, xx xx, xx xx, xx xx, xx xx, xx xx, xx

n x x x x x X

Visit 2

Mean xx.x xx.x xx.x xx.x xx.x xx.x

SD xx.x xx.x xx.x xx.x xx.x xx.x

Median xx.X xx.X xx.X xx.X xx.X xx.X

Min,Max xx, xx xx, xx xx, xx xx, xx xx, xx xx, xx

n x x x x x x

bslval value change

PART III

Output to Table

%anyTL( PROF.sex‘Sex, n(%)’/safety@1,treat, )(1) What if I don’t like the output by %anyTL?

• With the 3rd parameter (Table xx.xx) missing, a dataset (_anyTL) will be output,

DATA _anyTL; SET _anyTL;

RUN;

Demographic Parameters

Treatment A(N=345)

Treatment B(N=353)

Table 1Demographics

Safety Population

Notes: There is a central location where the title and footnote for all table/figure/listings can be found. It is OK to have more than 10 lines of footnotes. %anyTL will output them correctly.

Sex, n(%)

Male 345 (100) 219 (62.0) 564 (80.1)

Female 0 134 (38.0) 134 (19.9)

345(100.0)

_name_ _1 (treatment A) _2 (treatment B) _3 (Placebo)

_1=TRANWRD(_1, ‘(100)’, ‘(100.0)’); DROP _3; **do not display Placebo group;

%anyTL( , , Table 1)

/sasprog/study/output/table/t_01.lst

• with the 3rd parameter only to output a table

• modify _anyTL with data steps

Table 1 Demographics Safety Population … Notes: There is a central... It is OK to have more than 10 … …

Table 2 Title 1 for table 2 Title 2 for table 2 … Footnote 1 for table 2 Footnote 2 for table 2 …

Table 3 Title 1 for table 3 Title 2 for table 3 … Footnote 1 for table 3 Footnote 2 for table 3 …

Table 4 Title 1 for table 4 Title 2 for table 4 … Footnote 1 for table 4 Footnote 2 for table 4 …

……. …. …. … … … …

Treatment A(N=XXX)

Treatment B(N=XXX)

%anyTL( xxxx, xxxxx, Table 1 ‘Demographic Parameters’);

(2) How %anyTL add title/footnote and N to output table?

titles

• Look up for the corresponding title/footnotes in the central title/footnote dataset

Table 1Demographics

Safety Population

footnotes

Table 1

Colum

n Hea

der

Safety Population

(N=256) (N=378)

from PROF datasetwhere

safety=1

Age (years)

Mean xx.x xx.x

SD xx.x xx.x

Median xx.x xx.x

Min,Max xx, xx xx, xx

n x x

‘Demographic Parameters’

Notes: There is a central location where the title and footnote for all table/figure/listings can be found. It is OK to have more than 10 lines of footnotes. %anyTL will output them correctly.

%anyTL( REASON. reason‘Reason line1~This is the second line’/PROF.safety@1, treat, Table 11 ‘Header 1 ~ Header2’)

(3) Automatic Wrapping / Indentation

• Default split sign is ‘~’• Indent by one space at wrapped lines

Table 11Table example for Wrapping Long Text

Safety Population

Treatment A(N=XXX)

Treatment B(N=XXX)

Reason line1 This is the second line

Header 1 Header2

Reason 1 text is very long, will be wrapped (with indentation)

xx (xx.x) xx (xx.x)

Reason 2 text is also very long, will be wrapped (with indentation)

xx (xx.x) xx (xx.x)

Reason 3 text is short xx (xx.x) xx (xx.x)

(4) Smart Page Split

• Every block will not be split across page!

(5) More Than One Header Column %anyTL( CLIN. region*country-*(itt’N’@1/1# clinrsp’’/region*country*itt@1#+mienur),

treat,

Table 11 ‘Region/Country’-’Clinical Response’)

%anyTL( CLIN. region*country>0-*(itt@1/1# clinrsp’’/region*country*itt@1#+mienur), treat, Table 14.4.1.3 ‘Region/Country’/18-’Clinical Response’/20)

(6) Automatic/Specified Column width

• If not specified, %anyTL will determine the width automatically! • Alternatively, you can specify after the header text

1820

PART IV

Create a Listing quickly(leave the 1st parameter blank)

%anytl(, sae.treat‘Treatment Group' pid'Subject ID' (aged’/’ sex/~racec)'Age/Sex/Race' (fdsdt/~ldsdt)'Date of First/Last Dose of Study Drug' (pt91/ ae)'Preferred Term/Investigator Term‘/20 aedt'SAE Start/Stop Date'/or (aestrday/aestpday)'Day of SAE~Start/~Stop' death'Caused Death?' (sev/~aerel)'Severity/~Relationship to Study Drug' action'Action Taken with Study Drug', Table 14.5.2.4 );

/order order=data;Just indicate the LAST

order variableOther options: DOR=Descending NOPRINT ORDER

NP=NOPRINT ORDER

PG=BREAK AFTER xxx/PAGE

Combine multiple variables in the ( ) into one column. ‘text’ or special characters like blanks, /, etc. (‘’ not needed, ~ is the split sign) can be inserted between variables

/width=20;Otherwise

automatically assign the width

%anytl(,prof.rsn_drgc'Primary Reason for Discontinuation'/28 treat'Treatment Group'/or pt'Subject ID' ('header1' ('header2.1' riskclss'PORT Risk Class' dur_sty'Days on Study Drug’) ('header2.2' lastday'Study Day of Last Visit' (ctocresp " and " rtocresp)'Clinical/Radiographic Outcome at TOC’)),Table 14.1.5A );

A header that spans several

columns

To Insert a constant Text in the combined

variable

If dataset name not specified, the last used dataset before macro

call will be used

%anytl(, _NULL_."In case the dataset is empty, display this text in the center" medhis.param'Parameter' ce'Population Flag' treat'Treatment' (aged/sex/race)'Age/Sex/Race' (fdsdt/ldsdt)'First/Last Dose Date', Listing 16.1.4);

Or %anytl(, medhis.param'Parameter' ce'Population Flag' treat'Treatment' (aged/sex/race)'Age/Sex/Race' (fdsdt/ldsdt)'First/Last Dose Date‘ _NULL_."In case the dataset is empty, display this text in the center", Listing 16.1.4);

• Versatile

• Flexible

•Logical

• Succinct

• Easy to remember

Please tell me your suggestions!

Chen, YangSr. programmerTel: (201)253-6625snail_chen@hotmail.com

%anyTL

PART V

More details (optional)

(1) Different Source Data Sets and Select Display Range (continued)%anyTL(

pmmitt.sspecyn'Number of Subjects with a Sputum Sample Obtained, N1 (%) (1)'@1/prof.safety@1#

(sspecyn'Total Number of Individual Samples, N2'@1/1 sgsyn'Total Number of Individual Samples with Gram Stain, N3 (2)'@1/sspecyn@1)

tsampleg'Number of Subjects with (3)'/prof.safety@1#

asample'Number of Subjects with (N5)'/prof.safety@1#

result'Result of Gram’s Stain (5)'/sgsyn@1#,

Treat, Table 14.2.12 'Assessments');

(2) Different Source Data Sets and Select Display Range(continued)• Be default, ALL possible combinations of classes will be presented even if count is 0, but may produce unwanted combinations

%anyTL(eff.region*country*outcome/region*country*safety@1#, treat, Table 14.5.1.2);

• use >0 option to limit to the combination that exist in the input data%anyTL(eff.region*country>0*outcome/region*country*safety@1#, treat, Table 14.5.1.2);

(2) Different Source Data Sets and Select Display Range(continued)• If >0 option is put at the end, then only non-zero count will be displayed:

%anyTL(eff.region*country*outcome/region*country*safety@1#>0, treat, Table 14.5.1.2);

%anyTL( AE.teae’Subjects with at least one TEAE’ @1/PROF.safety@1# socterm[ac]**prefterm[dn@2**@3]/PROF.safety@1#, treat**severity, Table 14.5.1.4);

(3) Sort AE

• aeterm [sorting options] for each level• ac - ascending alphabetically (default) dc - descending alphabetically• an - ascending count dn - descending count@2 – by the sum of the count of the columns under treat=2@2**@3 – by the count of the column of treat=2 and severity=3@2**@2@3 – by the count sum of the column of treat=2 and severity in (2, 3)

%anyTL( prof.agegrp’Age’// safety@1, (treat+total)*sex, Table 14.2.1);

(4) Total column

%anyTL( prof.agegrp’Age’// safety@1, treat*(sex+total), Table 14.2.1);

(4) Total column

%anyTL( prof.agegrp’Age’// safety@1, (treat+total)*(sex+total), Table 14.2.1);

(4) Total column

%anyTL( prof.age sex’Sex, n(%)’/safety@1, treat+total@1@2, Table 14.2.1 ’Demographic or Baseline Parameter’);

(4) Total column (select range for total column)

foot

note

s

210

%anyTL( prof.age sex’Sex, n(%)’/safety@1, treat@1@2+total, Table 14.2.1 ’Demographic or Baseline Parameter’);

(4) Total column (select range for total column)

foot

note

s

210

%anytl(PROF.d_rank'Risk Class, n (%)'/itt@1 d_score'Overall Disease Severity Score' f_sign'Subjects with at least One Systemic Sign, n (%)'@1/itt@1 (wound1'Subjects with Abscess, N1'@2/1 f_abs5' At Least One Dimension >5cm, n (%) (1)'@1/wound1@2) f_sevr'Subjects with 2+ Signs and Symptoms at Baseline of Severe , n (%)'@1/itt@1, treat+total, );

%anytl(PROF.f_sign2'Subjects with 2+ Signs and Symptoms at Baseline of Severe, Fever~, or Elevated WBC Count (>10,000 cells/mm^3), n (%)'@1/itt@1 agegrp'Subjects Age <=75 Years, n (%)'@1/itt@1 agegrp'Subjects Age >75 Years, n (%)'@2/itt@1,treat+total,Table 14.2.41);

(4) Call the macro multiple times prior to Table production

• Before table number is specified, all results will be appended.

• When the table is output, all temporary datasets will be discarded.

(5) If you don’t want to use the default &protlib.d.d_prof for big N

%anyTL( xxxx, bign_data.treat, Table xxxx);

1. Create a source data set for big NDATA bign_data; SET &protlib.d.d_prof; WHERE itt=1 and riskclss=2;RUN;

2. Add the dataset name in the second parameter, separated by ‘.’

%anyTL( AE. aeterm1** aeterm2** aeterm3**aeterm4/PROF.safety@1#, treat*sex**severity,

Table 14.5.1.4);

(6) Where is the big N located?

TREAT and SEX are found in D_PROF, while SEVERITY is not in D_PROF

(7) How to display special characters(% & ‘ “) in quotation marks

Correct Quotation Display‘Example’ “Example”

Example

‘%compliance’‘%%compliance’

“%%compliance ”

%compliance

“%compliance ” may cause error since it is a Macro Call

“AT&T” ATxx (only if T can be resolved to xx,

otherwise there will be warning message)

‘AT&T’ AT&T

“ Gram’s Test” Gram’s Test

‘ Grams” Test’ Grams” Test

(8) Multiple pages (when too many columns cannot fit on one page)

%anyTL( &protlib.d.d_vitals.param*anvis*bsvalue|value, treat+total, Table 14.2.5A/3)

3 columns per page

(8) Multiple pages (continued)

%anyTL( &protlib.d.d_vitals.param*anvis*bsvalue|value, treat+total, Table 14.2.5A/4)

4 columns per page

(9) Output by categories %anyTL( &protlib.d.d_vitals.param*anvis*bsvalue|value|change, treat+total/’Gender: ’sex, Table 14.2.5A)

Output table in the order of a category variableNote: N is different by category

(9) Output by categories (combination with multiple page function)

%anyTL( &protlib.d.d_vitals.param*anvis*bsvalue|value|change, treat+total/’Gender: ’sex, Table 14.2.5A/3)

%anyTL( xxxxxxxxxxx, xxxxx, Table 14.4.1.2) -> validation dataset & table%TBLSTR(Table 14.4.1.2);%COMPSTR;

(10) Validation (Refer to my “Three Step Table Validation”)

Recommended