Sélection de variables : une introduction

Download nbviewer Onyxia
Binder Open In Colab githubdev

</p>

Pour illustrer le travail de données nécessaire pour faire de la sélection de variables, nous allons partir du même jeu de données que précédemment, c’est-à-dire les résultats des élections US 2020 présentés dans l’introduction de cette partie: les données de vote aux élections présidentielles US croisées à des variables socio-démographiques. Le code est disponible sur Github.

Le code est disponible sur Github.

In [2]:
#!pip install geopandas

import requests

url = 'https://raw.githubusercontent.com/linogaliana/python-datascientist/master/content/course/modelisation/get_data.py'
r = requests.get(url, allow_redirects=True)
open('getdata.py', 'wb').write(r.content)

import getdata
votes = getdata.create_votes_dataframes()
ERROR 1: PROJ: proj_create_from_database: Open of /miniconda/envs/python-ENSAE/share/proj failed

Jusqu’à présent, nous avons supposé que les variables utiles à la prévision du vote Républicain étaient connues du modélisateur. Nous n’avons ainsi exploité qu’une partie limitée des variables disponibles dans nos données. Néanmoins, outre le fléau computationnel que représenterait la construction d’un modèle avec un grand nombre de variables, le choix d’un nombre restreint de variables (modèle parcimonieux) limite le risque de sur-apprentissage.

Comment, dès-lors, choisir le bon nombre de variables et la meilleure combinaison de ces variables ? Il existe de multiples méthodes, parmi lesquelles :

  • se fonder sur des critères statistiques de performance qui pénalisent les modèles non parcimonieux. Par exemple, le BIC.
  • techniques de backward elimination.
  • construire des modèles pour lesquels la statistique d’intérêt pénalise l’absence de parcimonie (ce que l’on va souhaiter faire ici).

Principe du LASSO

Principe général

La classe des modèles de feature selection est ainsi très vaste et regroupe un ensemble très diverse de modèles. Nous allons nous focaliser sur le LASSO (Least Absolute Shrinkage and Selection Operator) qui est une extension de la régression linéaire qui vise à sélectionner des modèles sparses. Ce type de modèle est central dans le champ du Compressed sensing (où on emploie plutôt le terme de L1-regularization que de LASSO). Le LASSO est un cas particulier des régressions elastic-net dont un autre cas fameux est la régression ridge. Contrairement à la régression linéaire classique, elles fonctionnent également dans un cadre où $p>N$, c’est à dire où le nombre de régresseurs est très grand puisque supérieur au nombre d’observations.

Pénalisation

En adoptant le principe d’une fonction objectif pénalisée, le LASSO permet de fixer un certain nombre de coefficients à 0. Les variables dont la norme est non nulle passent ainsi le test de sélection.

Première régression LASSO

Avant de se lancer dans les exercices, on va éliminer quelques colonnes redondantes, celles qui concernent les votes des partis concurrents (forcément très corrélés au vote Républicain…) :

In [3]:
df2 = votes.loc[:,~votes.columns.str.endswith(
  ('_democrat','_green','_other', 'per_point_diff', 'per_dem')
  )]

Validation croisée pour sélectionner le modèle

Quel $\alpha$ faut-il privilégier ? Pour cela, il convient d’effectuer une validation croisée afin de choisir le modèle pour lequel les variables qui passent la phase de sélection permettent de mieux prédire le résultat Républicain.

In [15]:
print("alpha optimal :", lcv.alpha_)
alpha optimal : 0.001

Les variables sélectionnées sont :

In [17]:
print(features_selec2)
['ALAND', 'AWATER', 'votes_gop', 'diff', 'Rural-urban_Continuum Code_2003', 'Rural-urban_Continuum Code_2013', 'Urban_Influence_Code_2013', 'Economic_typology_2015', 'CENSUS_2010_POP', 'N_POP_CHG_2013', 'N_POP_CHG_2016', 'N_POP_CHG_2017', 'N_POP_CHG_2018', 'N_POP_CHG_2019', 'Births_2011', 'Births_2015', 'Deaths_2015', 'Deaths_2017', 'Deaths_2018', 'NATURAL_INC_2012', 'NATURAL_INC_2013', 'NATURAL_INC_2014', 'NATURAL_INC_2016', 'NATURAL_INC_2018', 'INTERNATIONAL_MIG_2010', 'INTERNATIONAL_MIG_2011', 'INTERNATIONAL_MIG_2012', 'INTERNATIONAL_MIG_2013', 'INTERNATIONAL_MIG_2014', 'INTERNATIONAL_MIG_2015', 'INTERNATIONAL_MIG_2016', 'INTERNATIONAL_MIG_2017', 'INTERNATIONAL_MIG_2018', 'INTERNATIONAL_MIG_2019', 'DOMESTIC_MIG_2010', 'DOMESTIC_MIG_2012', 'DOMESTIC_MIG_2013', 'DOMESTIC_MIG_2015', 'DOMESTIC_MIG_2016', 'DOMESTIC_MIG_2018', 'NET_MIG_2011', 'NET_MIG_2014', 'NET_MIG_2018', 'NET_MIG_2019', 'RESIDUAL_2010', 'RESIDUAL_2011', 'RESIDUAL_2012', 'RESIDUAL_2013', 'RESIDUAL_2014', 'RESIDUAL_2015', 'RESIDUAL_2016', 'RESIDUAL_2017', 'RESIDUAL_2018', 'RESIDUAL_2019', 'GQ_ESTIMATES_BASE_2010', 'GQ_ESTIMATES_2013', 'GQ_ESTIMATES_2015', 'GQ_ESTIMATES_2017', 'R_birth_2011', 'R_birth_2013', 'R_birth_2014', 'R_birth_2016', 'R_birth_2017', 'R_birth_2019', 'R_death_2011', 'R_death_2012', 'R_death_2013', 'R_death_2014', 'R_death_2015', 'R_death_2016', 'R_death_2017', 'R_death_2018', 'R_death_2019', 'R_NATURAL_INC_2012', 'R_NATURAL_INC_2015', 'R_NATURAL_INC_2017', 'R_NATURAL_INC_2018', 'R_NATURAL_INC_2019', 'R_INTERNATIONAL_MIG_2011', 'R_INTERNATIONAL_MIG_2012', 'R_INTERNATIONAL_MIG_2013', 'R_INTERNATIONAL_MIG_2014', 'R_INTERNATIONAL_MIG_2015', 'R_INTERNATIONAL_MIG_2016', 'R_INTERNATIONAL_MIG_2017', 'R_INTERNATIONAL_MIG_2018', 'R_INTERNATIONAL_MIG_2019', 'R_DOMESTIC_MIG_2011', 'R_DOMESTIC_MIG_2012', 'R_DOMESTIC_MIG_2013', 'R_DOMESTIC_MIG_2015', 'R_DOMESTIC_MIG_2016', 'R_DOMESTIC_MIG_2018', 'R_NET_MIG_2014', 'R_NET_MIG_2017', 'R_NET_MIG_2019', '2003 Rural-urban Continuum Code', 'Less than a high school diploma, 1970', 'High school diploma only, 1970', 'Some college (1-3 years), 1970', 'Four years of college or higher, 1970', 'Percent of adults with less than a high school diploma, 1970', 'Percent of adults with a high school diploma only, 1970', 'Percent of adults completing some college (1-3 years), 1970', 'Percent of adults completing four years of college or higher, 1970', 'Less than a high school diploma, 1980', 'High school diploma only, 1980', 'Some college (1-3 years), 1980', 'Four years of college or higher, 1980', 'Percent of adults with less than a high school diploma, 1980', 'Percent of adults with a high school diploma only, 1980', 'Percent of adults completing some college (1-3 years), 1980', 'Percent of adults completing four years of college or higher, 1980', 'Less than a high school diploma, 1990', 'Percent of adults with less than a high school diploma, 1990', 'Percent of adults with a high school diploma only, 1990', 'Less than a high school diploma, 2000', 'High school diploma only, 2000', "Some college or associate's degree, 2000", "Bachelor's degree or higher, 2000", 'Percent of adults with less than a high school diploma, 2000', 'Percent of adults with a high school diploma only, 2000', "Percent of adults completing some college or associate's degree, 2000", "Percent of adults with a bachelor's degree or higher, 2000", 'Less than a high school diploma, 2015-19', 'High school diploma only, 2015-19', "Some college or associate's degree, 2015-19", "Bachelor's degree or higher, 2015-19", 'Percent of adults with less than a high school diploma, 2015-19', 'Percent of adults with a high school diploma only, 2015-19', "Percent of adults completing some college or associate's degree, 2015-19", "Percent of adults with a bachelor's degree or higher, 2015-19", 'Metro_2013', 'Unemployed_2000', 'Unemployment_rate_2000', 'Unemployment_rate_2001', 'Unemployed_2002', 'Unemployment_rate_2002', 'Unemployed_2003', 'Unemployment_rate_2003', 'Civilian_labor_force_2004', 'Employed_2004', 'Unemployment_rate_2004', 'Civilian_labor_force_2005', 'Unemployed_2005', 'Unemployment_rate_2005', 'Civilian_labor_force_2006', 'Unemployed_2006', 'Unemployment_rate_2006', 'Unemployed_2007', 'Unemployment_rate_2007', 'Unemployed_2008', 'Unemployment_rate_2008', 'Employed_2009', 'Unemployment_rate_2009', 'Employed_2010', 'Unemployment_rate_2010', 'Civilian_labor_force_2011', 'Employed_2011', 'Unemployed_2011', 'Civilian_labor_force_2012', 'Employed_2012', 'Unemployed_2012', 'Unemployment_rate_2012', 'Unemployed_2013', 'Unemployment_rate_2013', 'Unemployed_2014', 'Unemployment_rate_2014', 'Civilian_labor_force_2015', 'Employed_2015', 'Unemployment_rate_2015', 'Unemployed_2016', 'Unemployment_rate_2016', 'Unemployed_2017', 'Unemployment_rate_2017', 'Unemployed_2018', 'Unemployment_rate_2018', 'Unemployment_rate_2019', 'Med_HH_Income_Percent_of_State_Total_2019', 'Rural-urban_Continuum_Code_2003', 'Urban_Influence_Code_2003', 'Rural-urban_Continuum_Code_2013', 'POVALL_2019', 'CI90LBALL_2019', 'CI90UBALL_2019', 'CI90LBALLP_2019', 'CI90UBALLP_2019', 'POV017_2019', 'CI90LB017_2019', 'CI90UB017_2019', 'CI90LB017P_2019', 'CI90LB517_2019', 'CI90UB517_2019', 'PCTPOV517_2019', 'CI90LB517P_2019', 'CI90LBINC_2019', 'CI90UBINC_2019', 'candidatevotes_2000_republican', 'candidatevotes_2004_republican', 'candidatevotes_2008_republican', 'candidatevotes_2012_republican', 'candidatevotes_2016_republican', 'share_2000_republican', 'share_2008_republican', 'share_2012_republican', 'share_2016_republican']
In [18]:
df2.select_dtypes(include=np.number).drop("per_gop", axis = 1).columns[np.abs(lasso2.coef_)>0]
nlasso = sum(np.abs(lasso2.coef_)>0)
print(nlasso)
206
print("Cela correspond à un modèle avec {} variables sélectionnées.".format(int(nlasso)))

Cela correspond à un modèle avec 206 variables sélectionnées.