Les Tests Statistiques en SAS
Les Tests Statistiques en SAS
Les Tests Statistiques en SAS
Raphaël Busson (Université de Caen) GNU General Public License Photographie de Yair Haklai
Aide
1 Tests de normalités 6
1.1 Proc univariate. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
12 Analyses intermédiaires 41
12.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
12.2 Correction de Pocock (non-recommandé) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
12.3 Correction de O’Brien et Flemming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
12.4 Correction de Lan et Demets (Pocok) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
12.5 Correction de Lan et Demets (O’Brien et Flemming) . . . . . . . . . . . . . . . . . . . . . . . . . . 43
12.6 Correction power family . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
12.7 Correction de Peto - Haybittle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
12.8 Méthode de triangulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Chapitre 1
Tests de normalités
• Kolmogorov-Smirnov
• Cramer-von Mises
• Anderson-Darling
Chapitre 2
Chapitre 3
3.3 Test du χ2
On dispose de d’une variable qualitative. Je rappelle que pour pouvoir utiliser ce test, il faut que les
effectifs théoriques soient supérieur à 5. Si ce n’est pas le cas, mais que la variable est ordinales, utilisez le
test χ2 de Mantel-Haenszel page 9. Si la variable n’a que deux modalités on peut utilisé le test exacte de
Fisher page 15 (attention ce test est gourmand en calculs).
A noter que cette commande fournit aussi le test de Student quand il est possible.
Chapitre 4
α
α2 =
k
Cette correction possède une puissance très légèrement inférieur à la correction de Dunn-Šidák. Attention,
l’hypothèse H0 est les deux échantillons ne sont pas différent et H1 est les deux échantillons sont différent.
Il ne faut absolument pas dire si on rejette H0, les deux échantillons sont significativement différents pour
la variable V1 au risque α.
1
α2 = 1 − (1 − α) k
Cette correction possède une puissance très légèrement supérieur à la correction de Bonferroni. Attention,
l’hypothèse H0 est les deux échantillons ne sont pas différent et H1 est les deux échantillons sont différent.
Il ne faut absolument pas dire si on rejette H0, les deux échantillons sont significativement différents pour
la variable V1 au risque α.
Chapitre 5
Chapitre 6
Chapitre 7
/*ou*/
/*ou*/
/*ou*/
Chapitre 8
/*ou*/
Avec la proc corr vous n’aurez que les résultats du test bilatéral.
Chapitre 9
Voici une macro que j’ai récupéré sur le site du Mayo Clinic College of Medicine. Elle est disponible sur
cette page1 (testé le 25/09/2014). Je n’est pas réécrit la macro, elle vous est donc donnée sous un autre style
que le mien, j’ai tout de même mis mon code couleur et mon indentation pour faciliter la lecture. Elle effectue
un test de symétrie d’une distribution et suggère des transformations par élévation à une puissance pour
améliorer la symétrie. Cette macro demande un grand nombre de calculs, elle ne convient pas (actuellement)
si l’échantillon dépasse 200 individus (j’ai testé avec 150 et 300).
%let data=;
%let var=;
%let out=;
%macro symmchk(data=,var=,out=_dumpout);
%local errorflg;
%LET errorflg = 0;
proc sql;
create table work._t as select * from dictionary.titles
where type='T';
reset noprint;
quit;
proc sql;
reset noprint;
1 www.mayo.edu/research/documents/symmchksas/doc-10027875
%LET TITLE1= ;
data _null_;
set _t;
%IF (&T>=1) %THEN %DO I=1 %TO &T;
if number=&I then call symput("TITLE&I", trim(left(text)));
%END;
run;
%LET TNEW = 1;
%LET TOTALT = %EVAL(&T + &TNEW);
%IF &TOTALT<=10 %THEN %LET TSHOW=&T;
%ELSE %LET TSHOW = %EVAL(10 - &TOTALT + &T);
%LET NEXTT1=%EVAL(&TSHOW+1);
%macro symm_out(datatemp=,chkvar=,cutp=, outd=, outp=1);
proc datasets;
delete _tmp7 _tmp6 _tmp3 _tmp2 _tmp1 _tmp0 _ddd _ddd2
_ddd3 _ddd4 _ddd5 _ddd6;
run;
quit;
proc datasets;
delete _tmp8_1 _ddda _dddb _dd23 _dd13 _dd12 _dd1 _dd2 _dd3;
run;
quit;
term2=(totaln-3)/(totaln-4)*bsum2;
term3=(totaln-1)*(totaln-2)*totaln/6;
term4=(totaln-3)*(totaln-4)*(totaln-5)/totaln/(totaln-1)/(totaln-2);
Var=TERM1+TERM2+TERM3-(1.0-TERM4)*T*T;
skew4=T/sqrt(var);
prob=2*(1.0-probnorm(abs(skew4)));
call symput('cutp',prob);
%mend symm_out;
newvar4=&var**4;
newvar5=&var**(1./2);
newvar6=&var**(1./3);
newvar7=&var**(1./4);
newvar8=log(&var+1);
newvar9=(&var+1)**(-1./2);
newvar10=(&var+1)**(-1./3);
newvar11=(&var+1)**(-1./4);
newvar12=1./(&var+1);
newvar13=1./(&var+1)**2;
newvar14=1./(&var+1)**3;
newvar15=1./(&var+1)**4;
%local cutpp;
%symm_out(datatemp=_use1,chkvar=newvar1,cutp=&cutpp,outd=_out1,outp=1);
_out14(in=in14) _out15(in=in15);
if in1 then do; cat=1 ; lab="Original "; end;
if in2 then do; cat=2 ; lab="Square "; end;
if in3 then do; cat=3 ; lab="3rd power "; end;
if in4 then do; cat=4 ; lab="4th power "; end;
if in5 then do; cat=5 ; lab="square root"; end;
if in6 then do; cat=6 ; lab="3rd root "; end;
if in7 then do; cat=7 ; lab="4th root "; end;
if in8 then do; cat=8 ; lab="log "; end;
if in9 then do; cat=9 ; lab="1/square rt"; end;
if in10 then do; cat=10; lab="1/3rd root "; end;
if in11 then do; cat=11; lab="1/4th root "; end;
if in12 then do; cat=12; lab="1/original "; end;
if in13 then do; cat=13; lab="1/square "; end;
%end;
title1;
%IF (&T>=1) %THEN %DO I=1 %TO &T;
title&I "&&TITLE&I";
%END;
%exit:
run;
%mend symmchk;
%symmchk(data=&data,var=&var,out=&out);
d’interactions la limite est facilement franchie puisque les termes sont évidemment corrélés, avec les variables
composant le terme d’interactions. Il faut ignorer ce critère pour les termes d’interactions si l’une
des variables principales est dans le modèle.
La fonction glm ne donne que la tolérance de type I et de type II. La tolérance pour le calcul du V IF
est la tolérance de type II.
data _null_;
set work._stabi_coef_out_res;
call symput("row",_n_);
if n>1 then call symput("suppr"||left(_n_), ",'"||left(&id)||left("'"));
else call symput("suppr"||left(_n_), "'"||left(&id)||left("'"));
run;
%let suppr=;
%do i =1 %to &row;
%let suppr=&suppr &&suppr&i;
%end;
data work._stabi_coef_out_res;
set &table;
if &id not in (&suppr) then output;
run;
%stabi_coef (
table=&table, id=&id, cible=&cible, var_explicative=&var_explicative,
alpha_influence=&alpha_influence, class=&class
);
Chapitre 10
data _null_;
set work._roc_comp_out_f;
call symput('test', n(format));
call symput('formc', format);
run;
data _null_;
set work._roc_comp_t (where=(fmtname="&formc"));
call symput(cats('c', _n_), label);
run;
%end;
%else %do;
proc freq data=&ap noprint;
table &cible / out=work._roc_comp_t;
run;
data _null_;
set work._roc_comp_t (where=(n(&cible)=1));
call symput(cats('c', _n_), cats(&cible));
run;
%end;
by &id;
run;
data work._logtol_out;
set work._logtol_out;
w=_p*(1-_p);
run;
%logtol(table=&table, var_explique=&var_explique,
var_explicative_discrete=&var_explicative_discrete, var_explicative=&var_explicative);
Chapitre 11
11.1 Log-rank
Ce test est un teste du log-rank. Dans le code suivant la variable var_temps prend la date de survenue
de d’événement (le décès), ou le délai avant la survenue de l’événement ; ou pour les personnes qui n’ont
pas eu la survenue de cette événement la date ou le délai à partir duquel on censure l’individu (perd leurs
traces, changement d’adresse, arrêt de l’étude...). La variable var_censure prend des valeurs numériques.
On défini une liste de valeurs correspondantes aux différentes censures possibles. Dans l’exemple suivant les
valeurs sont 1 et 2. On peut parfaitement définir une seule valeur pour tous les types de censures. La variable
var_strate permet de différencier les individus des deux groupes.
Pour le test en lui même, il est conseillé d’observer la p-value du Log-rang.
%macro tim2evnt(dsn,tim2evnt,censor,treat1);
*************************************;
** Macro to compute Prentice-Wilcoxon;
** test for pair-matched data.;
** STATKING Consulting, Inc.;
** October 199;
** dsn= data set name;
** tim2evnt = variable containing;
** time to event information;
** censor = variable containing;
** censor information;
** treat1 = value of first treatment;
*************************************;
proc sort data=&dsn; by &tim2evnt;
run; ** compute s_sub_i and score for each point;
data &dsn; set &dsn nobs=nobs;
retain s_sub_i 1;
** get time to event for last obs;
lasttime=lag(&tim2evnt);
** compute s_sub_i;
if ((lasttime ˆ= &tim2evnt) and (&censor ˆ= 1)) then
** nsubj / (nsubj+1);
s_sub_i=s_sub_i*((nobs-_n_+1)/(nobs-_n_+2));
** compute score;
if (&censor=1) then score=1-s_sub_i;
else score=1-(2*s_sub_i);
drop lasttime;
run;
proc sort data=&dsn; by subject treatmnt;
run;
end;
** compute delta_sub_l, sum of delta_sub_l
and; ** sum of delta_sub_l squared;
if last.subject then do;
delta=score1-score2;
delta2=delta**2;
if (delta ˆ= .) then do;
sumd=sumd+delta;
sumd2=sumd2+delta2;
end;
** output scores and summations;
output;
end;
** end of data, compute z statistic and probability;
if eof=1 then do;
z=sumd/(sqrt(sumd2));
probz=2*(1-probnorm(abs(z)));
call symput('z',put(z,4.2));
call symput('probz',put(probz,6.4));
end;
drop &tim2evnt score treatmnt &censor z probz;
run;
%mend tim2evnt;
Chapitre 12
Analyses intermédiaires
12.1 Introduction
On effectue des analyse intermédiaire pour pouvoir arrêter une étude si les tests sont concluant avant la
fin. On économise du temps et de l’argent.
La correction de Bonferonni et de Dunn-Šidák ne s’applique pas ici car les tests ne sont pas dépendant
car une partie des individus qui sont testé au test n + 1 ont été testé au test n.
Sas ne donne pas le α corrigé mais les borne du test centré réduit.
proc seqdesign;
design nstages=4 /*nombre de tests*/
method=poc
alt=twosided /*ou lower, upper*/
stop=both
/*si l’on veux des bornes d’arret pour non amelioration et non degradation*/
alpha=0.05 beta=0.10;
run;
proc seqdesign;
design nstages=4 /*nombre de tests*/
method=obf
alt=twosided /*ou lower, upper*/
stop=both
/*si l’on veux des bornes d’arret pour non amelioration et non degradation*/
alpha=0.05 beta=0.10;
run;
Tab. 12.3: Valeur théorique des α corrigés par la méthode de O’Brien et Flemming
proc seqdesign;
design nstages=4 /*nombre de tests*/
method=errfuncpoc
alt=twosided /*ou lower, upper*/
stop=both
/*si l’on veux des bornes d’arret pour non amelioration et non degradation*/
alpha=0.05 beta=0.10;
run;
proc seqdesign;
design nstages=4 /*nombre de tests*/
method=errfuncobf
alt=twosided /*ou lower, upper*/
stop=both
/*si l’on veux des bornes d’arret pour non amelioration et non degradation*/
alpha=0.05 beta=0.10;
run;
proc seqdesign;
design nstages=4 /*nombre de tests*/
method=pow(rho=0.25) /*0 Pocok, 0.25 O’Brien et Flemming */
alt=twosided /*ou lower, upper*/
stop=both
/*si l’on veux des bornes d’arret pour non amelioration et non degradation*/
alpha=0.05 beta=0.10;
run;
proc seqdesign;
design nstages=4 /*nombre de tests*/
method=peto(z=3.89) /*alpha_2*/
proc seqdesign;
design nstages=4 /*nombre de tests*/
method=tri(tau=1)
alt=twosided /*ou lower, upper*/
stop=both
/*si l’on veux des bornes d’arret pour non amelioration et non degradation*/
alpha=0.05 beta=0.10;
run;
Chapitre 13
13.1 Introduction
Pour ce genre de comparaison on utilise le score de propension. Le score de propension est la probabilité
qu’un sujet appartienne apriori, au groupe qui a subi une intervention, étant données ses caractéristiques.
data ps_weight;
set ps_p;
if group=1 then ps_weight=1/ps_pred;
else ps_weight=1/(1-ps_pred);
run;
run;
data ps_weight2;
if _n_=1 then set q;
retain mn_wt;
set ps_weight;
wt2=ps_weight/mn_wt; * Normalized weight;
run;
proc ttest;
by ps_pred_rank;
class group;
var outcome;
ods output statistics=strata_out;
data weights;
set strata_out;
if class='Diff (1-2)';
wt_i=1/(StdErr**2);
wt_diff=wt_i*Mean;
data total2;
set total;
Mean_diff = sum_diff/sum_wt;
SE_Diff = SQRT(1/sum_wt);
data one;
set ps_p;
ranvar=ranuni(0);
data all;
merge id_t ps_t id_c ps_c;
caliper=.10; * Note: caliper for matching is specified here;
array treat_id {*} tid1-tid5;
array ctl_id {*} cid1-cid8;
array treat_p {*} tps1-tps5;
array ctl_p {*} cps1-cps8;
array used_i {*} used1 - used8;
array matched_t {*} m_tid1-m_tid5;
array matched_c {*} m_cid1-m_cid5;
match_N=0;
do i=1 to 5;
min_diff=1;
best_match=0;
do j=1 to 8;
if used_i[j]=. then do;
if ABS(treat_p[i]-ctl_p[j])<caliper then do;
if ABS(treat_p[i]-ctl_p[j])<min_diff then do;
min_diff=ABS(treat_p[i]-ctl_p[j]);
best_match=j;
end;
end;
end;
end;
if best_match>0 then do;
match_N=match_N+1;
used_i[best_match]=1;
matched_t[match_N]=treat_id[i];
matched_c[match_N]=ctl_id[best_match];
end;
end;
data matches;
set all;
array matched_t {*} m_tid1-m_tid5;
array matched_c {*} m_cid1-m_cid5;
do match=1 to match_N;
Treatment_IDN=matched_t[match];
Control_IDN=matched_c[match];
output;
end;
keep match treatment_idn control_idn;
proc print;
var match treatment_idn control_idn;
title 'Matched Observations in Treatment and Control Groups';
run;
h.defineDone();
call missing(&idC, &pscoreC);
end;
/* Open the treatment */
set _PSMatching_Treatment;
%if %upcase(&method) ~= RADIUS %then %do;
retain BestDistance 99;
%end;
/* Iterate over the hash */
rc= iter.first();
if (rc=0) then BestDistance= 99;
do while (rc = 0);
/* Caliper */
%if %upcase(&method) = CALIPER %then %do;
if (&pscoreT - &caliper) <= &pscoreC <= (&pscoreT + &caliper) then do;
ScoreDistance = abs(&pscoreT - &pscoreC);
if ScoreDistance < BestDistance then do;
BestDistance = ScoreDistance;
IdSelectedControl = &idC;
MatchedToTreatID = &idT;
end;
end;
%end;
/* NN */
%if %upcase(&method) = NN %then %do;
ScoreDistance = abs(&pscoreT - &pscoreC);
if ScoreDistance < BestDistance then do;
BestDistance = ScoreDistance;
IdSelectedControl = &idC;
MatchedToTreatID = &idT;
end;
%end;
%if %upcase(&method) = NN or %upcase(&method) = CALIPER %then %do;
rc = iter.next();
/* Output the best control and remove it */
if (rc ~= 0) and BestDistance ~=99 then do;
output;
%if %upcase(&replacement) = NO %then %do;
rc1 = h.remove(key: IdSelectedControl);
%end;
end;
%end;
/* Radius */
%if %upcase(&method) = RADIUS %then %do;
if (&pscoreT - &caliper) <= &pscoreC <= (&pscoreT + &caliper) then do;
IdSelectedControl = &idC;
MatchedToTreatID = &idT;
output;
end;
rc = iter.next();
%end;
end;
run;
/* Delete temporary tables. Quote for debugging */
proc datasets nolist;
delete _PSMatching_:(gennum=all);
run;
%mend PSMatching;
%PSMatching(nom_table_sortie=&nom_table_sortie, datatreatment=&datatreatment,
datacontrol=&datacontrol, method=&method,numberofcontrols=&numberofcontrols,
caliper=&caliper, replacement=&replacement, idT=&idT, idC=&idC,
pscoreT=&pscoreT, pscoreC=&pscoreC);
data _TreatControl;
set Treatment(rename=(idT= id pscoreT= pscore ageT= age))
Control(rename=(idC= id pscoreC= pscore ageC= age));
run;
data _Control;
set _Control0;
DistCol = compress('d' || _N_);
run;
proc sql;
create table MatchedOpt as
select b.idC as IDSelectedControl, a.idT as IDTreatment
from result a left join _Control b
on a._ASSIGN_ = b.DistCol;
quit;