top of page

Sélection du candidat : régression multiple et estimation de la performance


Nous l'avons vu (ici), la régression linéaire simple peut nous fournir des informations sur la force et le signe d'une association linéaire entre une variable prédictive et une variable dépendante. Néanmoins, et contrairement à un modèle de régression linéaire simple, un modèle de régression linéaire multiple nous permet d'évaluer la force et le signe des associations entre deux (ou plus) variables prédictives et une variable dépendante. Ce faisant, en utilisant la régression linéaire multiple, nous pouvons déduire l'association entre une variable prédictive et une variable dépendante tout en contrôlant statistiquement les associations entre les autres variables prédictives et la même variable dépendante. De plus, la valeur des différents coefficients nous renseigne sur l'influence qu'a chacune des variables prédictives sur la variable dépendante et nous permet de faire des prévisions plus précises.



Un mot sur les hypothèses et le problème de la colinéarité


Les hypothèses statistiques qui doivent être vérifiées avant d'interpréter les résultats issues du modèle de régression multiple sont à peu de chose près les mêmes qu'avec la régression linéaire simple, ils comprennent :

  • Les individus sont issues d'un échantillons aléatoire dans la population, de sorte que les valeurs des variables pour un individu sont indépendants des valeurs des variables d'un autre individu ;

  • Les données sont exemptes de valeurs aberrantes ;

  • L'association entre les variables prédictives et dépendantes est linéaire ;

  • Il n'y a pas de (multi)colinéarité entre les variables prédictives ;

  • La valeur moyenne de l'erreur résiduelle est nulle pour tous les niveaux des variables prédictives ;

  • Les variances des erreurs résiduelles sont égales pour tous les niveaux des variables prédictives (homoscédasticité) ;

  • Les erreurs résiduelles sont normalement distribuées pour tous les niveaux des variables prédictives.

La quatrième hypothèse statistique concerne le concept de colinéarité (ou multicolinéarité). Cela peut être un concept délicat à comprendre, alors je vais prendnre un moment pour l'expliquer. Lorsque deux variables prédictives ou plus sont spécifiées dans un modèle de régression, comme c'est le cas pour la régression linéaire multiple, il faut être attentifs à la colinéarité. La colinéarité désigne la mesure dans laquelle les variables prédictives sont corrélées entre elles. Un certain niveau d'intercorrélation entre les variables prédictives est à prévoir et acceptable ; cependant, si la colinéarité devient importante, elle peut affecter les poids - et même les signes - des coefficients de régression dans notre modèle, ce qui peut poser problème d'un point de vue interprétation. Par conséquent, nous devrions éviter d'inclure des prédicteurs dans un modèle de régression linéaire multiple qui sont fortement corrélés entre eux. La statistique dite de "tolérance" est couramment calculée et sert d'indicateur de colinéarité. Elle est calculée en déterminant la variance partagée (R2) des seules variables prédictives dans un seul modèle (en excluant la variable dépendante), et en soustrayant cette valeur R2 de 1 (c'est-à-dire 1 - R2). Nous commençons généralement à nous inquiéter lorsque la statistique de tolérance tombe en dessous de 0,20 et se rapproche de 0,00. Idéalement, nous voulons que la statistique de tolérance se rapproche de 1,00, car cela indique qu'il y a des niveaux plus faibles de colinéarité. De temps en temps, vous pourriez également voir le facteur d'inflation de la variance (VIF) rapporté comme indicateur de colinéarité ; le VIF n'est que l'inverse de la tolérance (c'est-à-dire 1/tolérance), et à mon avis, il est redondant de rapporter et d'interpréter à la fois la tolérance et le VIF.



Un mot sur le jeu de données


Le dataframe contient 5 variables et 300 cas (c'est-à-dire, des employés) : EmployeeID, SJT, EI, Interview et Performance. Supposons que ces données ont été collectées dans le cadre d'une étude de validation simultanée visant à estimer la validité critériée des outils de sélection (par exemple, procédures, évaluations, tests) ; cela signifie que les outils de sélection (c'est-à-dire, SJT, EI, Interview) ont été administrés aux titulaires de postes et que la mesure critère (Performance) a été administrée à peu près au même moment. Pour commencer, EmployeeID est la variable identifiant unique. La variable SJT contient les scores d'un test de jugement situationnel conçu pour évaluer les concepts psychologiques de l'intelligence émotionnelle et de l'empathie ; les scores potentiels sur cette variable pourraient varier de 1 (faible intelligence émotionnelle et empathie) à 10 (intelligence émotionnelle et empathie). La variable EI contient les scores d'une évaluation de l'intelligence émotionnelle ; les scores potentiels sur cette variable pourraient varier de 1 (faible intelligence émotionnelle) à 10 (forte intelligence émotionnelle). La variable Interview contient les scores d'un entretien structuré conçu pour évaluer le niveau de compétences interpersonnelles des personnes interviewées ; les scores potentiels sur cette variable pourraient varier de 1 (compétences interpersonnelles médiocres) à 15 (compétences interpersonnelles excellente). Enfin, le critère pour cette étude de validation simultanée est la variable Performance, qui contient les évaluations de la performance professionnelle des titulaires de postes ; les scores potentiels sur cette variable pourraient varier de 1 (ne répond pas aux normes de performance) à 30 (dépasse les normes de performance).


import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import statsmodels.api as sm
import numpy as np
from pandas.plotting import lag_plot
from statsmodels.stats.outliers_influence import \ 
variance_inflation_factor

df = pd.read_csv(".../SelectionMultiple.csv")

df.info() 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 300 entries, 0 to 299
Data columns (total 5 columns):
 #   Column       Non-Null Count  Dtype 
---  ------       --------------  ----- 
 0   EmployeeID   300 non-null    object
 1   SJT          300 non-null    int64 
 2   EI           300 non-null    int64 
 3   Interview    300 non-null    int64 
 4   Performance  300 non-null    int64 
dtypes: int64(4), object(1)
memory usage: 11.8+ KB


Modélisation et check des hypothèses


# Define the dependent variable (y) and independent variables (X)
y = df['Performance']
X = df[['SJT', 'EI', 'Interview']]

# Add a constant term to the independent variables
X = sm.add_constant(X)

# Fit the multiple linear regression model
model = sm.OLS(y, X).fit()

fitted_values = model.fittedvalues
residuals = model.resid

Avant d'interpréter les résultats, on vérifie que les hypothèses du modèles sont vérifié. Rappelez vous que ces hypothèse vous permettent de vous rassurer sur la fiabilité du modèle. Si certaines ne sont pas vérifiées, ne vous arrêtez pas ! De plus, on peut toujours apporter des modifications au jeu de données pour l'améliorer et rendre certaines hypothèses valident (nous verrons ici comment régler un problème de colinéarité).


Check la distribution des résidus :

sns.displot(residuals, kde=True, color='blue', bins=20)
plt.title('Distribution des résidus')
plt.xlabel('Résidus')
plt.ylabel('Fréquence')
plt.show()

Sur ce premier graphique, montrant la distribution des résidus, nous pouvons déterminer si oui ou non nous avons satisfait l'hypothèse statistique selon laquelle les résidus sont normalement distribués. Nous voyons un histogramme et une distribution de densité de nos résidus avec la forme d'une distribution normale superposée. Comme vous pouvez le voir, nos résidus présentent une distribution principalement normale, ce qui est excellent et conforme à l'hypothèse.



Check la linéarité des résidus :

sns.scatterplot(x=fitted_values, y=residuals, s=75, edgecolor='k', alpha=0.6)
plt.axhline(y=0, color='r', linestyle='--', lw=1)
plt.title('Residuals vs Fitted Values')
plt.xlabel('Fitted Values')
plt.ylabel('Residuals')
plt.show()

Si vous vous en souvenez, les résidus sont l'erreur dans nos estimations - ou en d'autres termes, à quel point nos valeurs prédites pour la variable dépendante s'écartent des valeurs observées (réelles) pour la variable dépendante. Le terme "valeurs ajustées" est une autre façon de dire les valeurs prédites pour la variable dépendante. La ligne pointillée horizontale est tracée à la valeur résiduelle de zéro ; rappelez-vous, notre objectif est de minimiser la taille des résidus (c'est-à-dire, l'erreur). La ligne pleine montre les écarts par rapport à zéro des résidus pour chaque valeur ajustée, et plus la ligne pleine s'écarte de la ligne pointillée, plus il est probable que (a) les variances des résidus peuvent ne pas être égales pour tous les niveaux des variables prédictives (violation de l'hypothèse d'homoscédasticité), (b) la valeur moyenne de l'erreur résiduelle peut ne pas être nulle pour tous les niveaux de la variable prédictive, et (c) il peut y avoir des valeurs aberrantes multivariées potentielles influençant les valeurs ajustées (prédites).



Check des relations linéaires des différentes variables indépendantes avec la variables dépendante :

# Create scatterplots with regression lines
fig, axes = plt.subplots(1, 3, figsize=(15, 5))

sns.regplot(ax=axes[0], x='SJT', y='Performance', data=df)
axes[0].set_title('Performance vs. SJT')

sns.regplot(ax=axes[1], x='EI', y='Performance', data=df)
axes[1].set_title('Performance vs. EI')

sns.regplot(ax=axes[2], x='Interview', y='Performance', data=df)
axes[2].set_title('Performance vs. Interview')

# Show the plots
plt.show()

On voit une relation linéaire pour chaque variable indépendante avec la variable "performance". L'hypothèse de linéarité est vérifiée.


Nous devons maintenant nous intéressé à la corrélation entre les variables. On peut tracer une matrice de corrélation pour observer les liens entre les variables.


Matrice de corrélation :

# Calculate the correlation matrix
corr_matrix = df.corr()

# Create a custom color map
cmap = sns.diverging_palette(230, 20, as_cmap=True)

# Create the correlation matrix heatmap
plt.figure(figsize=(8, 6))
sns.heatmap(corr_matrix, annot=True, cmap=cmap, 
            vmin=-1, vmax=1, square=True, 
            linewidths=0.5, cbar_kws={"shrink": 0.8})

# Set the title and axis labels
plt.title('Correlation Matrix')
plt.xlabel('Variables')
plt.ylabel('Variables')

# Show the plot
plt.show()

La corrélation entre SJT et Interview est de 0,24, et la corrélation entre Interview et EI est de 0,32, ce qui est acceptable d'un point de vue colinéarité. En revanche, la corrélation entre SJT et EI est ÉNORME, à 0,93. En général, une corrélation de 0,85 ou plus peut indiquer que deux variables sont pratiquement indiscernables l'une de l'autre, et ici, la corrélation entre SJT et EI est de 0,93 ! Ces deux outils de sélection semblent mesurer la même chose et sont en grande partie redondants.



Check la colinéarité avec VIF et tolérance :

# Calcul le VIF pour chaque variable indépendante
vif_data = pd.DataFrame()
vif_data['Variable'] = X.columns
vif_data['VIF'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])]

# Calcul la tolérance de colinéarité
vif_data['Tolerance'] = 1 / vif_data['VIF']

# Affiche les résultats
print(vif_data)
    Variable        VIF  Tolerance
0      const  11.015333   0.090783
1        SJT   7.887216   0.126787
2         EI   8.277683   0.120807
3  Interview   1.145830   0.872730

Idéalement, nous voulons que la statistique de tolérance se rapproche de 1,00, car cela indique qu'il y a des niveaux de colinéarité plus faibles. Dans le tableau, nous pouvons voir que SJT a une statistique de tolérance de 0,127, ce qui est inférieur à 0,20 et indique que SJT chevauche considérablement les autres variables prédictives (EI, Interview) du modèle en termes de variance partagée. De même, EI a une statistique de tolérance problématique de 0,121, ce qui suggère un problème similaire. La tolérance pour Interview est de 0,873, ce qui suggère des niveaux faibles de colinéarité (ce qui est une bonne chose). Étant donné que SJT et EI ont tous deux des statistiques de tolérance faibles, dans cette situation, nous pouvons déduire qu'ils doivent être les coupables de la colinéarité. Et cela corrobore ce que nous avons vu dans la matrice de corrélation (voir ci-dessus). Ainsi, dans le modèle actuel, nous avons certainement un problème de colinéarité.


Comment déterminons-nous quel outil variable conserver ? Eh bien, cela dépend de plusieurs facteurs pratiques. Par exemple, nous serions probablement préoccupés par la quantité de ressources (par exemple, temps, argent) nécessaires pour administrer chacun de ces outils de sélection, et étant donné qu'ils sont apparemment redondants, nous pourrions choisir l'outil le moins gourmand en ressources. De plus, nous pourrions prendre en compte les réactions des candidats à chacun des outils. Si les candidats ont tendance à ne pas aimer l'un des outils ou à le percevoir comme injuste, alors cet outil pourrait être candidat à la suppression. Comme autre considération, nous pourrions vérifier si l'un de ces outils entraîne un impact défavorable (disparate), mais étant donné leur forte corrélation, si l'un entraîne un impact défavorable, l'autre le fera certainement aussi. Pour les besoins de ce post, supposons que nous avons une raison convaincante de supprimer EI et de conserver SJT. Il nous faut re-spécifié le modèle.



Re-spécification du modèle


# Défini la variable dépendante (y) et les variables indépendantes (X)
y2 = df['Performance']
X2 = df[['SJT', 'Interview']]

# Ajoute la constante aux variables indépendantes
X2 = sm.add_constant(X2)

# Ajuste le modèle
model2 = sm.OLS(y2, X2).fit()
                           OLS Regression Results                            
===================================================================
Dep. Variable:           Performance   R-squared:             0.264
Model:                           OLS   Adj. R-squared:        0.259
Method:                Least Squares   F-statistic:           53.34
Date:               Thu, 20 Apr 2023   Prob (F-statistic): 1.62e-20
Time:                       08:30:33   Log-Likelihood:      -752.98
No. Observations:                300   AIC:                   1512.
Df Residuals:                    297   BIC:                   1523.
Df Model:                          2                                         
Covariance Type:           nonrobust                                         
===================================================================
              coef    std err        t      P>|t|   [0.025   0.975]
-------------------------------------------------------------------
const       5.5265      0.539   10.249      0.000    4.465    6.588
SJT         0.5675      0.085    6.714      0.000    0.401    0.734
Interview   0.3853      0.064    6.031      0.000    0.260    0.511
===================================================================
Omnibus:                       82.881   Durbin-Watson:        2.139
Prob(Omnibus):                  0.000   Jarque-Bera (JB):   437.798
Skew:                           1.015   Prob(JB):          8.58e-96
Kurtosis:                       8.559   Cond. No.              25.9
===================================================================

Dans une situation réelle, nous procéderions de nouveau aux tests des hypothèses statistiques que nous avons effectués précédemment ; cependant, par souci de concision, nous supposerons que les hypothèses statistiques ont été raisonnablement satisfaites dans ce modèle re-spécifié dans lequel seules les variables SJT et Interview sont incluses en tant que prédicteurs.


En utilisant les estimations du coefficient de l'ordonnée à l'origine et des variables prédictives de notre modèle de régression linéaire multiple, nous pouvons écrire l'équation du modèle de régression comme suit :


Performance = 5.5265 + 0.5675*(SJT) + 0.3853*(Interview)



Prévision de la performance


Maintenant que nous avons notre modèle final, nous pouvons passez au scoring des candidat.

new_df = pd.read_csv(".../NouveauxCandidats.csv")
new_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 15 entries, 0 to 14
Data columns (total 3 columns):
 #   Column       Non-Null Count  Dtype 
---  ------       --------------  ----- 
 0   ApplicantID  15 non-null     object
 1   SJT          15 non-null     int64 
 2   Interview    15 non-null     int64 
dtypes: int64(2), object(1)
memory usage: 488.0+ bytes

# Sauvegarde les paramètres dans des variables
const = model2.params[0]
b0 = model2.params[1]
b1 = model2.params[2]

new_df["Prévision"] = const + (b0 * new_df["SJT"]) + \
(b1 * new_df["Interview"])
# Tri les valeurs par rapport à la colonne "prévision"
new_df.sort_values(by="Prévision", ascending=False).head()

Comme vous pouvez le voir, les candidats AA14, AA9 et AA12 ont les scores les plus élevés. Si nous avions un poste vacant à pourvoir, en utilisant cette approche, nous pourrions d'abord proposer ce poste à un de ces trois candidats.


N'oubliez jamais que c'est un outils d'aide à la décision. Le modèle mathématique permet de synthétiser plusieurs variables et de calculer une prévision. Lors du recrutement, beaucoup d'autres process (qui ne sont pas mesuré par votre organisation) entre en jeux. Le modèle est un guide mais la décision vous revient.

Comentarios


bottom of page