SAS編程-Table:頻數(shù)匯總表的總結(jié)

歡迎關(guān)注,SAS茶談!

在臨床試驗的Safety分析中,簡單的統(tǒng)計描述與頻數(shù)匯總的表格占據(jù)絕對的大頭。

頻數(shù)匯總表本質(zhì)是分子除以分母。在編程的第一步,需要搞明白表格中每個統(tǒng)計量的含義。在這個前提下,編程思路會很清晰。

分母一般是各人群試驗組的計數(shù),人群的篩選一般很直接,Title和Footnotes會有詳細說明。試驗分組的劃分中,有可能涉及匯總組(Total)的處理,常規(guī)有兩種方法,參考文章SAS編程:生成Table時,匯總組(Total)組如何處理?。

0. 分子的3種類別分類

分子是各類別的計數(shù),相對復(fù)雜一點。從類別數(shù)目角度看,我將其劃分為3類:固定類別非固定類別,以及固定與非固定類別結(jié)合。

固定類別是指,類別數(shù)目在Shell中已經(jīng)明確定。例如,以下這張AE Summary的表,左側(cè)輸出類別是清楚明確的。

AE Sum

非固定類別是指,類別數(shù)目在Shell中是未知的。例如,AE PT的受試者發(fā)生率的表,PT數(shù)目暫且未知,根據(jù)實際數(shù)據(jù)集內(nèi)容確定。

AE PT

固定與非固定類別結(jié)合是指,既含有固定類別,又含有非固定類別。例如,AE PT與毒性等級的受試者發(fā)生率的表,PT數(shù)目不確定,毒性等級數(shù)目確定。

AE by PT and Grade

不知道讀者對于這3類表格,是否有自己的編程思路。下面我來介紹一下,我對這三類表格的處理。

前2類簡單一點,讀者可以參考下文所提之前文章的處理;第3類復(fù)雜一點,會介紹的詳細一些。

1、固定類別的處理

常見的固定類別的table,除了上面舉例比較復(fù)雜的外,還有比較簡單的。例如,人口學(xué)的Race的頻數(shù)匯總。

Race

這里的“復(fù)雜”和“簡單”如何區(qū)分呢?如果分類條件涉及單個變量,我將其稱為簡單;分類條件涉及多個變量,稱為復(fù)雜

對于固定類別的Table,我建議大家嘗試,“簡單”地處理——將多變量條件轉(zhuǎn)化為單變量條件處理。

對于前面那張AE Sum的table,有19個類別。編程時,有人可能會嘗試直接調(diào)用19次單行計數(shù)的宏程序,然后將19個結(jié)果數(shù)據(jù)集進行拼接。這樣可以實現(xiàn),但編程效率有點低。

大家可以嘗試,新建一個變量(如,catn),其取值對應(yīng)每一個類別。這樣多變量條件就轉(zhuǎn)化成單變量條件,利用一個Means過程步就可以獲取到每個類別的計數(shù),簡潔高效很多。

這個方法可以參考之前介紹類似表格的處理,SAS編程-Table:受試者處置中止理由頻數(shù)匯總。

這里需要注意的是,對于固定類別的表格(試驗分組trt01an也屬于固定分類),計數(shù)頻數(shù)為0的情況也需要輸出。我習(xí)慣使用Means過程步中Class語句的Preloadfmt選項,具體參考鏈接文章中的程序介紹,計數(shù)的主要過程步如下:

proc means data = adae nway completetypes;
  format trt01an trt01an.;
  class trt01an / preloadfmt mlf order = data;

  format catn catn.;
  class catn / preloadfmt order = data;

  var flag;
  output n = count out = count1; 
run;

額外提一點,受試者發(fā)生率是人數(shù)除以人數(shù),前期處理分析數(shù)據(jù)時,需要對受試者進行去重。

proc sort data = adae1 out = adae nodupkey;
  by catn usubjid;
run;

2、非固定類別的處理

非固定類別與固定類別相比,很大的一點不同是,類別數(shù)目的不確定。這里不需要考慮所有可能的輸出結(jié)果,也就不需要“Preloadfmt”處理。

這也就自然引出了類別排序的問題,一般有兩種排序方式:1)按照某組別頻數(shù)降序排序;2)按照類別名稱進行排序。

排序一般在footnotes中有明確說明,若沒有,需要及時與統(tǒng)計師進行溝通確認。AE相關(guān)Table一般都是匯總組頻數(shù)降序排序。

處理這一類別的Table,F(xiàn)req和Means過程步都方便實現(xiàn)。我習(xí)慣使用Means過程步,方便試驗組別的生成。由于Means過程步分析變量只能處理數(shù)值變量,需要新建一個Flag變量以方便計數(shù)。

以上面舉例的PT表為例,前期數(shù)據(jù)處理需要注意兩點。第一,首行內(nèi)容的處理;第二,受試者的去重。

對于首行,我一般在Data步中通過新增記錄進行處理,這樣只需對一個數(shù)據(jù)集進行一次“Means”處理,就可以獲取想要的計數(shù)。參考代碼如下:

data adae;
  set adae1;

  length cat $200;
  cat1n = 1; cat = "Number of subjects reporting treatment-emergent adverse events"; output;
  cat1n = 2; cat = aedecod; output;
  
  flag = 1;

  proc sort nodupkey;
    by cat1n cat usubjid;
run;

計數(shù)時,為確保首行內(nèi)容排在第一列,分組變量加上cat1n。這里需要注意,不同的cat1n變量對應(yīng)不同的cat,所以cat1n變量不能用class語句進行分組,否則completetypes選項會帶來多余的組合,需使用by語句。讀者可以自行調(diào)試驗證下。

proc means data = adae nway completetypes;
  by cat1n;

  format trt01an trt01an.;
  class trt01an / preloadfmt mlf order = data;

  class cat;

  var flag;
  output n = count out = count1; 
run;

這里也可以不新建cat1n變量,直接在首行內(nèi)容前加上字符,使其字符排序時,排在前面。最后,在輸出結(jié)果中進行處理下。例如,添加“00-”:

cat = "00-Number of subjects reporting treatment-emergent adverse events";

后序的BigN計算、轉(zhuǎn)置、排序,這里就不詳細介紹,可以參考上一小節(jié)中的鏈接文章。

3、固定與非固定類別結(jié)合的處理

第3類是前兩者的結(jié)合,編程也是結(jié)合兩者的特點,過程復(fù)雜一些。上面舉例的Table中,涉及到某一類的AE以及最差等級的信息。這些內(nèi)容一般在ADAE中進行處理,TFL編程里直接引用變量條件,這里就不再介紹。

處理頻數(shù)表內(nèi)容,我首選是將復(fù)雜的變量條件轉(zhuǎn)化為簡單的變量條件,考慮排序的需要,會新建排序變量方便排序。

固定類別內(nèi)容需要輸出頻數(shù)為0的記錄,這一塊可以通過Means過程步中的Preloadfmt選項實現(xiàn)。

首先,需要新建對應(yīng)的Format??v向的試驗組別的信息也屬于固定類別,也是需要建立對應(yīng)的Format,匯總組的生成可以利用multilabel的選項。(試驗分組取值以1、2舉例)

***1. Create formats for output;
proc format;
  value trt01an (notsorted multilabel)
    1 = 1
    2 = 2
    1, 2 = 99
  ;

  value catn
    0 = 0
    1 = 1
    2 = 2
    3 = 3
    4 = 4
  ;

  value cat
    0 = "0"
    1 = "Grade >= 2"
    2 = "Grade >= 3"
    3 = "Grade >= 4"
    4 = "Fatal"
  ;
run;

第2步獲取分析數(shù)據(jù)集,有2個來源,用于計算BigN的ADSL,以及用于計算小n的ADAE。

ADSL 數(shù)據(jù)集選擇對應(yīng)的人群的記錄。

***2. Get data for analysis;

**2.1 Get data for BigN;
data  adsl;
  set adam.adsl;
  where xxxx and trt01an in (1, 2);
  
   *Flag for count;
    flag = 1;
run;

ADAE數(shù)據(jù)集需要將多變量條件轉(zhuǎn)化為單變量條件,最后需要對每一類計數(shù)的受試者ID去重。以這張Table的Shell為例,我會新建catn(0,1,2,3,4,5)變量來代表每一個類別,不同組塊的類別使用變量cat1n(1,2,3)變量。不同組塊的首行內(nèi)容展示也有區(qū)別,新建變量cat1進行處理。

**2.2 Get data for small n;
data adae;
   merge adam.adae(in = a) adsl(in = b keep = usubjid);
    by usubjid;
    if a and b and trtemfl = "Y" ;

     flag = 1;

    length cat1 $200;
    
    cat1n = 1; cat1 = "Number of subjects reporting treatment-emergent adverse events"; catn = 0; otuptut;

    if aecat = xxx then do;
       cat1n = 2; cat1 = "Any xxx Preferred Term";
        if 1 then do; catn = 0; otuput; end;
        if aetoxgrn >= 2 then do; catn = 1; output; end;
        if aetoxgrn >= 3then do; catn = 2; output; end;
        if aetoxgrn >= 4then do; catn = 3; output; end;
        if aetoxgrn = 5then do; catn = 4; output; end;

        cat1n = 3; cat1 = strip(aedecod);
        if 1 then do; catn = 0; otuput; end;
        if aetoxgrn >= 2 then do; catn = 1; output; end;
        if aetoxgrn >= 3then do; catn = 2; output; end;
        if aetoxgrn >= 4then do; catn = 3; output; end;
        if aetoxgrn = 5then do; catn = 4; output; end;
     end;

    proc sort nodupkey;    
        by cat1n cat1 catn usubjid;
run;

第3步統(tǒng)計量的計算,也就是大N和小n的計算。大N的值會用于小n百分比的計算以及Header中大N的展示。

對于固定類別(trt01an, catn),即便內(nèi)容在數(shù)據(jù)集中缺失,也是需要全部展現(xiàn)在表中,所以固定類別在Means過程步Class語句中使用preloadfmt選項;

對于非固定類別(cat1n),如果只與其他特定類別有關(guān)聯(lián)(cat1n=1, cat1="Number of XXX"; cat1n=2, cat1="Any XXX"; cat1n=3, cat1=aedecod.),分析分組使用by語句;

對于非固定類別(cat1),如果與其他所有類別(trt01an, catn)都有關(guān)聯(lián),分析分組使用class語句,completetypes選項會補齊所有可能結(jié)果。

如果采用Format過程步中的multilabel選項來構(gòu)建匯總組,對應(yīng)的class語句中需要添加mlf選項。

***3. Calculate statistics;

***3.1 Derive BigN and save them to macro vars;
proc means data = adsl nway completetypes;
    format trt01an trt01an.;
    class trt01an / preloadfmt mlf order = data;
    var flag;
    output n = bign out = BigN(keep = trt01an bign);
run;

data _null_;
   set BigN;
  call symputx("N_"||strip(trt01an), strip(put(bign, best.)) );
run;

小n的處理,在分析數(shù)據(jù)集處理好之后,生成過程不復(fù)雜。cat1n變量對應(yīng)不同的cat,所以cat1n變量不能用class語句進行分組,否則completetypes選項會帶來多余的組合,使用by語句進行分組。

**3.2 Calculate small n and percentage;

*Get small n;
proc means data = adae nway completetypes;
  by cat1n;

  format trt01an trt01an.;
  class trt01an/ preloadfmt mlf order = data;

  class cat1;

  format catn catn.;
  class catn / preloadfmt order = data;

  var flag;
  output n = count  out = count1;
run;

小n計算完成后,與BigN數(shù)據(jù)集拼接,計算百分比。完成后,需要排序,方便轉(zhuǎn)置。轉(zhuǎn)置的作用,是將橫向放置的Treatment分組信息縱向放置。

*Get percentage;
data count2;
  merge count1 bign;
  by trt01an;
  
  length freq $200;
  if bign ne 0 then freq = strip(put(count,best.))||" ("||strip(put(count/bign*100, 8.1)) || ")";
  else freq = "0 (-)";

  proc sort;
      by cat1n cat1 catn trt01an;
run;

進行轉(zhuǎn)置:

*Transpose results;
proc transpose data = count2 out = count3 prefix = trt_;
    by cat1n cat1 catn;
    var freq;
    id trt01an;
run;

轉(zhuǎn)置完成后,需要需要微調(diào)下數(shù)據(jù)集,包含Col1文本信息的處理、Cat1n = 1的情況中多余的Catn的記錄需要刪除(catn >= 1, 有Preloadfmt選項生成),以及需要為每一個Cat組新建一個頻數(shù)變量以后降序排序(Retain語句)。

data final1;
  set count3;
  
  by cat1n cat1;
  length c1-c3 $200;
  c1 = put(catn, cat.);
  c2 = trt_1;
  c3 = trt_2;
  c4 = trt_99;

  retain cat2n;
  if first.cat1 then cat2n = input(strip(scan(c3, 1,"(")), best.);

  if c1 = "0" then c1 = cat1;
  if cat1n = 1 and catn ne 0 then delete;

  proc sort;
    by cat1n descending cat2n cat1 cat;
run;

data final2;
  set final1;
  row_num = _n_;
  keep row_num c1-c4;
run;

接下來生成Header數(shù)據(jù)集,QC的內(nèi)容要包含大N的信息。

data header;
  row_num = 0;
  length c1 - c4 $200;

  c1 = "Preferred Term Worst Grade";
  c2 = "TRT A (N = &N_1.) n (%)";
  c3 = "TRT B (N = &N_2.) n (%)";
  c4 = "Total (N = &N_99.) n (%)";
run;

最后,生成QC數(shù)據(jù)集。

**4.2 Create dataset for QC;
data qc;
  set header final2;
run;

4. 其他

頻數(shù)匯總表涉及到的內(nèi)容,基本不出這3類情況。之前介紹的AE SOCPT的嵌套表格,是第二類非固定類別的處理;介紹的Shift表格,是第一類固定類別的處理;關(guān)于第三類固定與非固定結(jié)合,之前也有SOC、PT、Severity3層嵌套表格的介紹。

具體可以參閱對應(yīng)文章:

感謝閱讀, 歡迎關(guān)注:SAS茶談!
若有疑問,歡迎評論交流!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容