近期小编整理了一下生物等效性(BE)试验中PK分析部分的常规处理程序。于是就来分享一下这部分Winnonlin上的操作以及对应的利用SAS实现的程序。
BQL处理
在拿到样本检测数据后(浓度数据通常以Excel外部数据形式进行传输),将外部数据转化成SAS数据集,同时会对浓度数据中低于定量下限的BQL数据进行处理,根据方案中指定的规则进行BQL数据的替换,通常处理规则如下图。
BQL处理规则(摘自某方案)
上面截图为最常规的填补方式,也不乏有其他的花式填补。本文以最常规的填补方式为例。
winnonlin中的操作
在winnonlin中,选择数据选择>send to>Data Management>BQL。
选择BQL
在Main中设置SORT(受试者、周期/采血)、Time(采血时间点)、Concentration(浓度)、Carry(保留需要的变量)。
设置Main
设置填补规则,下图所示,设置Tmax前填补0,Tmax后填补ND。如果BQL无差别替换的话,将下图中的几个ND都替换成0即可。
设置替换规则
SAS中的代码
在SAS中,BQL的替换也是很简单的,下面来看看代码。
代码语言:javascript复制/****************************************************************************************************************************************
宏名称 : BQL
目的 : BQL填补
参数说明 :
inds 输入数据集
outds 输出数据集
con 浓度变量
time 时间变量(时间点,数值型)
treat 序列(T / R)
subjid 受试者编号
Keyword 关键词
bql1 填补方式1生成的变量
bql2 填补方式2生成的变量
YN 针对Tmax 之后出现的BQL
0:不考虑Tmax之后的连续BQL(统一按照缺失或者0处理)
1:考虑Tmax之后出现的连续BQL(连续出现的BQL之后的可测量结果填补ND,自身也ND)
Tmaxafter 限制Tmax之后出现的BQL
填补规则 :
第一种填补:将BQL全部替换成0
第二种填补:将Tmax之前的BQL替换成0,Tmax之后的BQL替换成ND
%bql(inds=adpc,outds=final,subjid=RANDNUM,
treat=TRTAL,con=AVAL,time=APCTIM,Keyword=BQL,bql1=BQL01,bql2=BQL02,YN=0);
________________________________________________________________________________________________________________________
__________________________________________________________________________________________________________________________
版本 日期 修改人 修改描述
--- ----------- ------------ ----------------------------------------------------------------------------------
1.0 2021.04.06 Setup 创建
****************************************************************************************************************************************/
%macro bql(inds=,outds=,subjid=,treat=,con=,time=,Keyword=BQL,bql1=AVAL01,bql2=AVAL02,YN=0,Tmaxafter=1);
data _temp_01;
set &inds.;
_temp_con=input(&con.,??best.);
run;
*计算Tmax时间点;
proc sql ;
create table _temp_02(where=(Cmax=_temp_con)) as
select distinct &subjid.,&treat.,&time.,_temp_con,max(_temp_con) as Cmax
from _temp_01 as a
group by &subjid.,&treat.;
create table _temp_03 as
select distinct a.*,Cmax,b.&time. as Tmax label="Tmax"
from _temp_01 as a
left join _temp_02 as b
on a.&subjid. =b.&subjid.
and a.&treat. =b.&treat. ;
quit;
proc sort data=_temp_03 out=_temp_03 sortseq=linguistic(numeric_collation=on);by &subjid. &treat. &time. ;quit;
data _temp_04;
set _temp_03;
by &subjid. &treat. &time. ;
retain missfl 0;
if first.&treat. then do;
*限制Tmax之后出现的连续的BQL;
if missing(_temp_con) %if &Tmaxafter. eq 1 %then %do;and &time.<=Tmax %end ; then missfl=0;
end;
else do;
if missing(_temp_con) %if &Tmaxafter. eq 1 %then %do;and &time.>Tmax %end ; then missfl=missfl 1;
%if &Tmaxafter. eq 1 %then %do;
else if missing(_temp_con) and &time.<=Tmax then missfl=0;
%end ;
else if ^missing(_temp_con) and missfl>=2 %if &Tmaxafter. eq 1 %then %do;and &time.>Tmax %end ; then missfl=missfl 1;
else if ^missing(_temp_con) and missfl<2 %if &Tmaxafter. eq 1 %then %do;and &time.>Tmax %end ; then missfl=0;
end;
run;
proc sort data=_temp_04 out=_temp_04 sortseq=linguistic(numeric_collation=on);by &subjid. &treat. descending &time. ;quit;
data _temp_04;
set _temp_04;
by &subjid. &treat. descending &time.;
missfllag1=lag(missfl);
if first.&treat. then call missing(missfllag1);
run;
proc sort data=_temp_04 out=_temp_05 sortseq=linguistic(numeric_collation=on);by &subjid. &treat. &time. ;quit;
data &outds.;
set _temp_05;
/*第一种填补方式:将所有的BQL当做0处理*/
&bql1.=&con.;
if index(upcase(&con.),"&Keyword.") then &bql1.="0";
/*考虑Tmax后连续2条BQL的情况--连续的俩条BQL之后的数据填补ND*/
%if &YN. eq 1 %then %do;
if missfl>=2 or (missfl=1 and missfllag1=2) then &bql1.="ND";
%end;
/*将Tmax之前的BQL替换成0,Tmax之后的BQL替换成ND*/
&bql2.=&con.;
if index(upcase(&con.),"&Keyword.") and &time.<Tmax then &bql2.="0";
else if index(upcase(&con.),"&Keyword.") and &time.>Tmax then &bql2.="ND";
%if &YN. eq 1 %then %do;
if missfl>=2 or (missfl=1 and missfllag1=2) then &bql2.="ND";
%end;
drop Cmax Tmax _temp_con missfllag1 missfl;
run;
proc delete data=work._temp_01 _temp_02 _temp_03 _temp_04 _temp_05 ;quit;
%mend;
在BQL填补完成后,就可以在winnonlin中进行PK参数的计算,这里小编就不截图演示了,PK参数的计算小编也没有用SAS实现过,在winnonlin中点点点就可以了。
多因素方差分析
在生物等效性评价中,通常会对Cmax、AUClast、AUCinf_obs进行对数转化后,进行多因素方差分析。
方差分析样表
winnonlin中的操作
如下图,在计算出PK参数后,按照下图所示的点选,然后选择对应的的变量,就能方差分析、单向双侧T检验、置信区间都计算出来,关于Tmax非参数检验将下图所选的改成Crossover即可。这里就不展示winnonlin中具体的操作。
选择Bioequivalence
SAS中的代码
在生物等效性分析中,一般采用Proc Mixed过程对数据进行分析。此处以常规的两制剂、单次给药、双周期、双交叉试验为例。下面以Cmax为例进行计算。
代码语言:javascript复制data _rungrpds;
set adam.adpp;
if besfl="是" and UPCASE(param)="CMAX".;
_temp_aval=Log(aval);
run;
%let subject=RANDNUM;*受试者变量;
%let trtseq=trtseq;*给药顺序;
%let period=period;*周期;
%let trtal=trtal;*制剂;
ods exclude all;
ods output type3=_temp_01;
proc mixed data=_rungrpds method=type3;
class &subject. &trtseq. &period. &trtal.;
model _temp_aval=&trtseq. &period. &trtal. ;
random &subject.(&trtseq.);
Lsmeans &trtal.;
run;
ods exclude none;
data _final;
length _param _top $200.;
set _temp_01;
_param="ln(Cmax)";
if upcase(Source)=upcase("&TRTSEQ.") then do _top="序列";SEQ=1;end;
else if index(Source,')') then do _top="受试者(序列)";SEQ=2;end;
else if upcase(Source)=upcase("&TRTAL.") then do _top="制剂";SEQ=3;end;
else if upcase(Source)=upcase("&PERIOD.") then do _top="周期";SEQ=4;end;
else do ; _top="误差";SEQ=5;end;
label _top="试验因素" _param="药代动力参数" ;
keep _top _param DF SS MS FValue ProbF SEQ ;
run;
proc sort data=_final out= _final sortseq=linguistic(numeric_collation=on);by SEQ;quit;
如上代码,即可实现Cmax相关的多因素方差分析。
输出结果(试验数据不展示了)
双向单侧T检验
下面来看一下第二个常规表格,双向单侧T检验,如下图所示。
双向单侧T检验样表
双向单侧T检验分析的实现也是较为简单的,采用PROC MIXED计算出参数,然后利用公式进行计算。采用此公式计算出来的结果与winnonlin结果数值是一致的(T2的正负除外)。
参考另外一篇文献,将T2公式稍改一下,即可得出与winnonlin一致的结果。
SAS中的代码
代码语言:javascript复制data _rungrpds;
set adam.adpp;
if besfl="是" and UPCASE(param)="CMAX".;
_temp_aval=Log(aval);
run;
%let subject=RANDNUM;*受试者变量;
%let trtseq=trtseq;*给药顺序;
%let period=period;*周期;
%let trtal=trtal;*制剂;
ods exclude all;
proc mixed data=_rungrpds;
class &subject. &trtseq. &period. &trtal.;
model _temp_aval=&trtseq. &period. &trtal. &subject.*&trtseq. /s ddfm=satterth ;
random intercept/subject=&subject. ;
lsmeans &trtal./diff=control('R') alpha=0.1 cl;
ods output diffs=_temp_diffs lsmeans=_temp_Lsmeans;
run;
ods exclude none;
proc sql UNDO_POLICY=NONE;
create table _temp_01 as
select distinct a.*,b.Estimate as Tmean,c.Estimate as Rmean
from _temp_diffs as a
left join _temp_Lsmeans(where=(&trtal.='T')) as b on 1=1
left join _temp_Lsmeans(where=(&trtal.='R')) as c on 1=1
;
quit;
data _temp_01;
set _temp_01;
/*Tost 值计算*/
t1_Tost=(input(Tmean,??best.)-input(Rmean,??best.)-log(0.80))/StdErr;
t1_TostP =1-probt(abs(t1_Tost),DF);
/*t2_Tost=(log(1.25)-(input(Tmean,??best.)-input(Rmean,??best.)))/StdErr;*书上公式,但算出来符号与winNonlin不一致;*/
t2_Tost=((input(Tmean,??best.)-input(Rmean,??best.))-log(1.25))/StdErr;
t2_TostP =1-probt(abs(t2_Tost),DF);
run;
置信区间法
常规表格三,生物等效性中的置信区间的计算,如下图所示。
置信区间样表
这部分的计算依然采用的是PROC MIXED过程步。这个表也是主要评价是否等效的一个关键表,下面来看一看这个表实现的过程。
SAS中的代码
代码语言:javascript复制
data _rungrpds;
set adam.adpp;
if besfl="是" and UPCASE(param)="CMAX";
_temp_aval=Log(aval);
run;
%let subject=RANDNUM;*受试者变量;
%let trtseq=trtseq;*给药顺序;
%let period=period;*周期;
%let trtal=trtal;*制剂;
ods exclude all;
proc mixed data=_rungrpds;
class &subject. &trtseq. &period. &trtal.;
model _temp_aval=&trtseq. &period. &trtal. ;
random &subject.(&trtseq.);
lsmeans &trtal./diff=control('R') alpha=0.1 cl;
ods output covparms=_temp_Covparms tests3=_temp_type diffs=_temp_diffs lsmeans=_temp_Lsmeans;
run;
ods exclude none;
/*T/R 几何均值*/
data _temp_01;
set _temp_Lsmeans;
Geomean=compress(put(round(exp(Estimate),0.001),12.3));
Mean=Estimate;
keep &trtal. Geomean Mean ;
run;
proc transpose data=_temp_01 out=_temp_01 prefix=AVAL;
by &trtal.;
var Geomean Mean;
run;
data _temp_01;
set _temp_01;
_nname_=strip(&trtal.)||strip(_NAME_);
run;
proc transpose data=_temp_01 out=_temp_01(drop=_name_) ;
var AVAL1;
id _nname_;
run;
/*T/R 例数*/
proc sql;
create table _temp_02 as
select distinct &trtal.,cats(count(distinct &subject. )) as n
from _rungrpds
group by &trtal.
order by &trtal. desc;
quit;
proc transpose data=_temp_02 out=_temp_02(drop=_name_) prefix=N;
var n;
id &trtal.;
run;
data _temp_03;
set _temp_diffs;
ratio=exp(Estimate);
Estimate2=exp(Estimate)*100;
Lower1=exp(Lower);
Upper1=exp(Upper);
keep Estimate2 ratio Lower1 Upper1 ;
run;
data _temp_Covparms;
set _temp_Covparms;
AVAL=sqrt(exp(Estimate)-1);
if CovParm="Residual" then do;n_name_="CV01";n_label_="个体内变异";end;
else do;n_name_="CV02";n_label_="个体间变异";end;
run;
proc transpose data=_temp_Covparms out=_temp_04 ;
var AVAL;
id n_name_ ;
idlabel n_label_ ;
run;
proc sql noprint;
select count(distinct &subject.) into :count trimmed from _rungrpds;
select ratio into :ratio trimmed from _temp_03;
select CV01 into :cv trimmed from _temp_04;
quit;
ods output output=_temp_05;
proc power;
twosamplemeans test=equiv_ratio
alpha = 0.05
lower = 0.8
upper = 1.25
meanratio = &ratio.
cv = &cv.
npergroup =&count.
power =.;
run;
ods exclude none;
data _final;
merge _temp_01-_temp_05;
run;
非参数检验
针对Tmax的分析,通常是采用配对非参数的方法进行差异性检验(指导原则)。winnonlin上的crossover出来的结果应该不是采用这个方法做的,本来试着去还原一下winnonlin的方法,但是尝试几次,始终结果不一致,就放弃。
指导原则上的要求
SAS中的代码
代码语言:javascript复制%let subject=RANDNUM;*受试者变量;
%let trtseq=trtseq;*给药顺序;
%let period=period;*周期;
%let trtal=trtal;*制剂;
data _rungrpds;
set adam.adpp;
if besfl="是" and UPCASE(param)="TMAX";
run;
proc sort data=_rungrpds out=_rungrpds ;by &subject. ;;quit;
proc transpose data=_rungrpds out=Temp01 ;
by &subject. ;
var AVAL;
id &trtal. ;
run;
data Temp01;
set Temp01;
DIF=R-T;
run;
ods exclude none;
ODS TRACE ON;
ODS output TestsForLocation=temp2;
proc univariate DATA=Temp01;
var DIF;
run;
ODS TRACE OFF;
ods exclude all;
总结
上面就是生物等效性分析中的常规表格,还有几张常规表格,基本就类似于清单一样直接输出,当然还有几张图,譬如药时曲线等,作图可见小编历史推文SAS-时药曲线的绘制、SAS-时药曲线的绘制(完)、SAS-临床试验程序绘图合集(一),也都是很简单的操作。另外小编这里也开通一项功能,承接临床试验数据分析(包括但不限于PK参数计算及分析等)。