Projet machine learning interprétable

Louis Guilbaud



Ce projet vise à créer des méthodes permettant d’interpréter les algorithmes de Machine Learning :


Tous les programmes peuvent s’adapter à toutes les méthodes de machine learning pour toutes les variables. Cependant il faut rester sur la prédiction d’une probabilité. En effet, pour la prédiction d’une variable continue la structure des tables est légèrement différente. Le programme pour les ALE catégorielle n’est cependant pas généralisable pour des raisons expliquer plus loin. Téléchargez le code SAS en cliquant ici et la base de données en cliquant ici. Pour éxécuter le code il suffit de changer le chemin d’accès vers la base de données

Partials Dependence Plot (PDP)


Les Partials Dependence Plot (PDP) montre l’effet marginal d’une ou deux variables sur la prédiction d’un modèle de machine learning.

\(\hat pd_s(X_s) = {1 \over n}\sum_n^{i=1} \hat f (X_s , X_c^{(i)})\)


Pour créer les PDP nous créons le macro programme PDP qui prend quatre paramètres :

%macro PDP(table,variable,cible,fichier);

On cherche d’abord à savoir quel est le type de la variable, c’est à dire si elle est caractère ou numérique. Par défaut dans notre programme les variables numériques seront traitées comme des variables continues et les variable caractères comme des variables qualitatives. On peut ainsi récupérer le type de la variable dans la macro-variable globale type.

  %globale type
    proc contents data=&table. 
                            out=type(KEEP=NAME TYPE where=(lowcase(STRIP(NAME))= "&variable.")) noprint;
    run;

    data _null_;
        set type;
        call symputx("type",type);
    run;

On récupère ensuite toutes les valeurs possibles de la variable à analyser afin que chaque individu soit dupliqué autant de fois qu’il y a de valeurs possibles. A chaque duplication la valeur de la variable à analyser sera modifier afin que la valeur de la variable à analyser soit différente à chaque duplication. Chaque individu prend donc touts les valeurs possibles pour la variable à analyser le reste restant inchangé.

    proc summary data = &table. noprint;
        class &variable.;
        output out=va_possibles (where=  (_TYPE_=1));
    run;
    

    data simulation;
        set va_possibles (drop=_type_ _freq_);
        do i=1 to n;
            set &table.(drop=&variable. &cible.) point=i nobs=n;
            %include "&fichier.";
            output;
        end;
    run;

Après avoir scorer toutes nos observations, on peut faire la moyenne de toutes les observations par valeurs possibles de la variable à analyser.

    proc summary data = simulation noprint;
        class &variable.;
        output out=PDP (where=(_type_ = 1)) mean(P_&cible.1)=avg_reponse;
    run;

Si la variable est quantitative on fait un graphique de type series, sinon on fait un graphique de type vbar.

    %if &type. =1 %then %do;
        proc sgplot data=PDP;
            series x = &variable. y = Avg_reponse /markers markerattrs=(symbol=circlefilled);
            Xaxis label="&variable." grid;
            Yaxis label="Probabillité prédite moyenne" grid;
            title "Partials Dependence Plot de la variable &variable";
        run;
        quit;
    %end;

    %if &type.=2 %then %do;
        proc sgplot data=PDP;
            vbar &variable. /response = Avg_reponse categoryorder = respdesc;
            Xaxis label="&variable." grid;
            Yaxis label="Probabillité prédite moyenne" grid;
            title "Partials Dependence Plot de la variable &variable";
        run;
        quit;
    %end;

%mend PDP;

On peut donc appliquer notre programme à la variable age de la base de données germandataset.

%PDP(dataset,age,creditRisk,&chemin.\DT.sas); 

On peut voir que l’âge à une influence sur la probabilité de défaut. La probabilité de défaut calculer par l’arbre de décision semble la moins élevé pour des âges entre 20 et 30 ans. Après cela la probabilité de défaut augmente légèrement jusqu’à 38 ans. Par la suite elle redescente avant de stabiliser pour un âge supérieur à 50 ans. Cette probabilité oscille entre 0.685 et 0.725.

On applique notre programme à la variable qualitative account status de la base de données germandataset.

%PDP(dataset,accountstatus,creditRisk,&chemin.\DT.sas);

La valeur de la variable accounstatus à une influence sur la probabilité prédite puisqu’elle est plus élevé pour les valeurs “A13” et “A14z que pour les valeurs”A12" et “A13”.


Individual Conditional Expectation (ICE)


Les Individual Conditional Expectation (ICE) affiche une ligne par individu qui montre comment la prédiction évolue lorsqu’une caractéritique change.

\(ICE_{s,i}(X_s) = \hat f (X_s , X_c^{(i)})\)


Pour créer les ICE nous créons le macro programme ICE qui prend cinq paramètres :

%macro ICE(table,variable,cible,nb,fichier);

Comme pour les PDP on duplique chaque individu autant de fois qu’il y a de valeurs possibles de la variable à analyser. A chaque duplication la valeur de la variable à analyser sera modifier afin que toutes les valeurs soient différentes. La seconde étape data, non présente pour les PDP, sert à numéroter les individus. Grace à cela on pourra regrouper toutes les duplications d’un même individu.

    proc summary data = &table. noprint;
        class &variable.;
        output out=va_possibles (where=(_TYPE_=1));
    run;
    
    data &table.2;
        set &table.(drop=&variable. &cible.);
        Num = _n_;
    run; 

    data simulation;
        set va_possibles (drop=_type_ _freq_);
        do i=1 to n;
            set &table.2 point=i nobs=n;
            %include "&fichier.";
            output;
        end;
    run;    

  proc summary data = simulation;
        class Num;
        output out=indiv (where=(_type_=1));
    run;

Ces étapes servent à afficher le nombre d’ICE voulu par une sélection aléatoire parmi tous les individus de la table.

    data indiv;
        set indiv;
        selection = ranuni(12345);
    run; 

    proc sort data = indiv;
        by selection;
    run;

    data selectionindiv;
        set indiv;
        if _N_ LE &nb.;
    run;

    proc sql;
        create table ICE as
        select *
        from selectionindiv  a left join simulation b on a.num=b.num
        order by num, &variable.;
    quit;

On peut ensuite afficher les ICE.

    proc sgplot data = ICE;
        series x=&variable. y =P_&cible.1 / group=num;
    run;
    quit;

%mend ICE;

On peut donc appliquer notre programme à la variable age de la base de données germandataset.

%ICE(dataset,age,creditRisk,10,&chemin.\DT.sas);

On a créé 10 ICE pour la variable age permettant ainsi de voir l’influence de la variable age sur plusieurs observations. Beaucoup d’observations sur ce graphique on une probabilité de défaut inchangé même si l’âge change.


On applique notre programme à la variable qualitative account status de la base de données germandataset.

%ICE(dataset,age,creditRisk,20,&chemin.\DT.sas);

On peut voir que plus le nombre d’ICE afficher (ici 20) est élevé moins le graphique est interprétable. Le changement de catégorie de la varibale accounstatus semble avoir une influence sur la probabilité prédite de plusieurs individus.


On peut afficher les ICE et PDP sur le même graphique pour comparer une ICE au PDP de la variable. Nous avons donc donc le macro-programme PDP_ICE, se servant des macro-programmes ICE et PDP.

%macro PDP_ICE(table,variable,cible,nb,fichier);
    %PDP(&table.,&variable.,&cible.,&fichier.);
    %ICE(&table.,&variable.,&cible.,&NB.,&fichier.);

    data PDP_ICE;
        set PDP(rename=(&variable.=&variable._PDP avg_reponse=avg_reponse_PDP))
            ICE (rename=(&variable.=&variable._ICE P_&cible.1=P_&cible.1_ICE));
    run;

  proc sgplot data=PDP_ICE;
    series x = &variable._PDP y =avg_reponse_PDP /lineattrs=(thickness=5);
    series x=&variable._ICE y =P_&cible.1_ICE / group=num name="ICE";
    Xaxis label="&variable." grid;
    Yaxis label="Probabillité prédite moyenne" grid;
    title "Partials Dependence Plot et ICE de la variable &variable";
  run;
  quit;
%mend;

On applique notre programme à la variable age.

%PDP_ICE(dataset,age,creditRisk,10,&chemin.\DT.sas);

La ligne bleu large représente le PDP et les 10 lignes plus fines représentent les ICE de 10 individus sélectionnés aléatoirement. On peut donc voir l’écart entre l’ICE d’un individu et le PDP de la variable age.


Accumulated Local Effects (ALE)



Les Accumulated Local Effects (ALE) décrivent comment une variable influence la prédiction d’un modèle de machine learning en moyenne, en prenant en compte la dépendance avec les autres variables explicatives.

\(\hat ALE_{s}(X) = \sum_{k=1}^{k_s(x)} {1 \over {n_s(k)}}\sum (\hat f (z_{k,s} , x_c^{(i)})-\hat f (z_{k-1,s} , x_c^{(i)}))\)


ALE sur variables quantitatives

Pour créer les ALE sur les variables quantitatives nous créons le macro programme ALE qui prend cinq paramètres :

  • table est le nom de la table d’apprentissage du modèle.
  • variable nom de la variable à analyser.
  • cible nom de la variable cible du modèle créé.
  • nb_divide Nombre d’intervale à créer.
  • fichier chemin vers le fichier de scoring.
%macro ALE(table,variable, cible, nb_divide,fichier);

Comme pour les PDP et les ICE on récupère toutes les valeurs possibles de la variable à analyser. On peut alors créer le nombre d’intervalles demandé dans les options du macro-programme. Chaque intervalle sera compris entre deux valeurs, une borne haute et une borne basse.

/* On récupère les toutes les valeurs possible de la variable*/
proc summary data = &table. noprint;
    class &variable.;
    output out=va_possibles (where=(_TYPE_=1));
run;

%macro cal_int;
    %do i=1 %to &nb_divide.;
        calculated int_%sysevalf(&i-1) + calculated taille_intervalle as int_&i.,
    %end;
%mend cal_int;
proc sql;
    create table min_max as
    select *,
    max(&variable.)-min(&variable.) as nb_va_possibles, 
    calculated nb_va_possibles/&nb_divide. as taille_intervalle,
    min(&variable.) as int_0, 
    %cal_int 
    1 as a  
    from va_possibles;
run;
quit;

On peut maintenant relier chaque observation à l’intervalle à laquelle elle appartient. On numérote également les observations afin de pouvoir les relier plus facilement par la suite.

%macro if_born;
%do i=1 %to &nb_divide.;
    if int_%sysevalf(&i-1)<=age<=int_&i. then do;
        born_inf=int_%sysevalf(&i-1);
        born_sup=int_&i.;
        born=&i.;
    end;
%end;
%mend if_born;
data min_max2;  
    set min_max;
    %if_born; 
run;

data &table.2;
    set &table.;
    Num = _n_;
run; 

proc sql;
    create table born_inf as
    select *
    from dataset2 a left join min_max2(keep=&variable. born_inf) b on a.&variable.=b.&variable.;

    create table born_sup as
    select *
    from dataset2 a left join min_max2(keep=&variable. born_sup) b on a.&variable.=b.&variable.;
quit;

On renomme les variables born_inf et born_sup age pour pouvoir scorer la table. Chaque observation de départ sera doublée afin d’en avoir une comportant la borne inférieure de l’intervalle à laquelle elle appartient en tant que variable âge et l’autre ayant la borne supérieure comme variable âge. On trie ensuite la table afin d’avoir la borne inférieure en premier suivi de la borne supérieur pour chaque individu.

data dataset_ALE;
    set born_inf(drop= &variable. rename=(born_inf=&variable.))
        born_sup(drop= &variable. rename=(born_sup=&variable.));
run;

proc sort data=dataset_ALE;
    by num &variable.;
run;

data ALE;
    set dataset_ALE;
    %include "&fichier.";
run;

On peut calculer la différence entre la probabilité prédite par la borne supérieur et la probabilité prédite par la borne inférieur.

data ALE;
    set ALE;
    by  num;
    lag=lag(P_&cible.1);
    if last.num then do;
        ALE_age= P_&cible.1-lag;
    end;
    if last.num;
run;

Pour chaque intervalle on calcule la moyenne de la différence entre la probabilité prédite par la borne supérieur et la probabilité prédite par la borne inférieur.

proc summary data = ALE noprint;
    class &variable.;
    output out=ALE_plot (where=(_type_ = 1)) mean(ALE_&variable.)=avg_reponse;
run;

On peut faire la somme cumulée de la moyenne avant de réaliser le graphique.

data ALE_plot;
    set ALE_plot;
    cum_avg_reponse+avg_reponse;
run;

proc sgplot data = ALE_plot;
    series x=&variable. y =cum_avg_reponse;
run;
quit;
%mend ALE;

On peut donc appliquer notre programme à la variable age de la base de données germandataset.

%ALE(dataset,age,creditrisk,30,&chemin.\DT.sas);

L’ALE a une forme similaire au PDP. Donc même en prenant en compte l’interaction avec les autres variables, la variable âge influe très légèrement su la probabilité prédite.


ALE sur variables qualitatives

Pour les ALE sur variables qualitatives : Le problème est de trouvé un ordre à la variable qualitative. On peut passer par des notions de distance mais à cause de la complexité de ces notions je donne un ordre à la variable accountstatus :
A11 < A12 < A13 < A14

Ce programme ne sera donc pas généralisable

On duplique chaque individu en lui faisant prendre la valeur inférieur et supérieur de accountstatus. Par exemple, si un individu à la valeur “A12” il sera trois fois dans la table, une fois avec “A11”(sa borne inférieur), une autre fois avec les valeurs “A12”(sa valeur actuelle) et une dernière fois avec la valeur “A13” (sa borne supérieur). La valeur des autres variables reste inchangée.

%macro ALE_quali;
    data dataset2;
        set dataset;
        num=_N_;
    run;

    data simulation1;
        set dataset2;
        if accountstatus="A11" then do;
            %do i=11 %to 12;
                accountstatus="A&i.";
                table=1;
                output;
            %end;
        end;
        
    run;

    data simulation2;
        set dataset2;
        if accountstatus="A12" then do;
            %do i=11 %to 13;
                accountstatus="A&i.";
                table=2;
                output;
            %end;
        end;
        
    run;

    data simulation3;
        set dataset2;
        if accountstatus="A13" then do;
            %do i=12 %to 14;
                accountstatus="A&i.";
                table=3;
                output;
            %end;
        end;
        
    run;

    data simulation4;
        set dataset2;
        if accountstatus="A14" then do;
            %do i=13 %to 14;
                accountstatus="A&i.";
                table=4;
                output;
            %end;
        end;

    run;

On peut maintenant regrouper les quatres tables créer et scorer toutes les observations.

    data simulation;
        set simulation1 simulation2 simulation3 simulation4;
    run;

data simulation;
    set simulation;
    %include "&chemin.\DT.sas";
run;

proc sort data=simulation;
    by num accountstatus;
run;

On calcul alors la différence entre la probabilité prédite de la valeur la plus basse avec la probabilité prédite de la valeur supérieur. On peut faire la moyenne de ces différences par individu.
La dernière étape data vise à ne garder qu’une observation par individu.

data simulation2;
    set simulation;
    by num;
    lag=lag(P_creditRisk1);
    diff=P_creditRisk1-lag;
    if first.num then delete;
run;

proc sql;
    create table ALE_quali as
    select num,
            table,
            accountstatus,
            mean(diff) as moyenne
    from simulation2
    group by num;
quit;

data ALE_quali;
    set ALE_quali;
    by num;
    if last.num then output;
run;

On s’assure que chaque individu à retrouver la valeur de accounstatus qu’il avait au départ. C’est à cela que sert la variable table créé précédemment. On peut ensuite faire la moyenne par valeur de accountstatus avant d’en faire la somme cumulée.

data ALE_quali;
    set ALE_quali;
    if table=1 then accountstatus="A11";
    if table=2 then accountstatus="A12";
    if table=3 then accountstatus="A13";
    if table=4 then accountstatus="A14";
run;

proc summary data = ALE_quali noprint;
    class accountstatus;
    output out=ALE_plot (where=(_type_ = 1)) mean(moyenne)=avg_reponse;
run;

data ALE_plot;
    set ALE_plot;
    cum_avg_reponse+avg_reponse;
run;

On peut maintenant réaliser al graphique de l’ALE.

proc sgplot data = ALE_plot;
    vbar accountstatus /response = cum_avg_reponse ;
    Xaxis label="accountstatus" grid;
    Yaxis label="Probabillité prédite moyenne" grid;
    title "Accumulated Local Effects de la variable accountstatus";
run;
quit;
%mend ALE_quali;

%ALE_quali;

Comme pour l’ALE sur une variable quantitative, la forme de l’ALE est simlaire au PDP trouvé plus haut. La changement de accountstatus influe la probabilité prédite.


Bibliographie

https://compstat-lmu.github.io/iml_methods_limitations/ale-misc.html

https://www.sas.com/content/dam/SAS/support/en/sas-global-forum-proceedings/2018/1950-2018.pdf