!pip install --upgrade xlrd #colab bug verson xlrd
!pip install geopandas
Le précédent chapitre visait à proposer un premier modèle pour comprendre les comtés où le parti Républicain l’emporte. La variable d’intérêt étant bimodale (victoire ou défaite), on était dans le cadre d’un modèle de classification.
Maintenant, sur les mêmes données, on va proposer un modèle de régression pour expliquer le score du parti Républicain. La variable est donc continue. Nous ignorerons le fait que ses bornes se trouvent entre 0 et 100 et donc qu’il faudrait, pour être rigoureux, transformer l’échelle afin d’avoir des données dans cet intervalle.
Ce chapitre utilise toujours le même jeu de données, présenté dans l’introduction de cette partie : les données de vote aux élections présidentielles américaines croisées à des variables sociodémographiques. Le code est disponible sur Github.
import requests
= "https://raw.githubusercontent.com/linogaliana/python-datascientist/main/content/modelisation/get_data.py"
url = requests.get(url, allow_redirects=True)
r open("getdata.py", "wb").write(r.content)
import getdata
= getdata.create_votes_dataframes() votes
Ce chapitre va utiliser plusieurs packages
de modélisation, les principaux étant Scikit
et Statsmodels
.
Voici une suggestion d’import pour tous ces packages.
import numpy as np
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
import sklearn.metrics
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
1 Principe général
Le principe général de la régression consiste à trouver une loi \(h_\theta(X)\) telle que
\[ h_\theta(X) = \mathbb{E}_\theta(Y|X) \] Cette formalisation est extrêmement généraliste et ne se restreint d’ailleurs par à la régression linéaire.
En économétrie, la régression offre une alternative aux méthodes de maximum de vraisemblance et aux méthodes des moments. La régression est un ensemble très vaste de méthodes, selon la famille de modèles (paramétriques, non paramétriques, etc.) et la structure de modèles.
1.1 La régression linéaire
C’est la manière la plus simple de représenter la loi \(h_\theta(X)\) comme combinaison linéaire de variables \(X\) et de paramètres \(\theta\). Dans ce cas,
\[ \mathbb{E}_\theta(Y|X) = X\beta \]
Cette relation est encore, sous cette formulation, théorique. Il convient de l’estimer à partir des données observées \(y\). La méthode des moindres carrés consiste à minimiser l’erreur quadratique entre la prédiction et les données observées (ce qui explique qu’on puisse voir la régression comme un problème de Machine Learning). En toute généralité, la méthode des moindres carrés consiste à trouver l’ensemble de paramètres \(\theta\) tel que
\[ \theta = \arg \min_{\theta \in \Theta} \mathbb{E}\bigg[ \left( y - h_\theta(X) \right)^2 \bigg] \]
Ce qui, dans le cadre de la régression linéaire, s’exprime de la manière suivante :
\[ \beta = \arg\min \mathbb{E}\bigg[ \left( y - X\beta \right)^2 \bigg] \]
Lorsqu’on amène le modèle théorique (\(\mathbb{E}_\theta(Y|X) = X\beta\)) aux données, on formalise le modèle de la manière suivante :
\[ Y = X\beta + \epsilon \]
Avec une certaine distribution du bruit \(\epsilon\) qui dépend des hypothèses faites. Par exemple, avec des \(\epsilon \sim \mathcal{N}(0,\sigma^2)\) i.i.d., l’estimateur \(\beta\) obtenu est équivalent à celui du Maximum de Vraisemblance dont la théorie asymptotique nous assure l’absence de biais, la variance minimale (borne de Cramer-Rao).
Exercice 1a : Régression linéaire avec scikit
Cet exercice vise à illustrer la manière d’effectuer une régression linéaire avec scikit
.
Dans ce domaine,
statsmodels
est nettement plus complet, ce que montrera l’exercice suivant.
L’intérêt principal de faire
des régressions avec scikit
est de pouvoir comparer les résultats d’une régression linéaire
avec d’autres modèles de régression. Cependant, le chapitre sur les
pipelines montrera qu’on peut très bien insérer, avec quelques efforts
de programmation orientée objet, une régression statsmodels
dans
un pipeline scikit
.
L’objectif est d’expliquer le score des Républicains en fonction de quelques variables. Contrairement au chapitre précédent, où on se focalisait sur un résultat binaire (victoire/défaite des Républicains), cette fois on va chercher à modéliser directement le score des Républicains.
- A partir de quelques variables, par exemple, ‘Unemployment_rate_2019’, ‘Median_Household_Income_2019’, ‘Percent of adults with less than a high school diploma, 2015-19’, “Percent of adults with a bachelor’s degree or higher, 2015-19”, expliquer la variable
per_gop
à l’aide d’un échantillon d’entraînementX_train
constitué au préalable.
⚠️ Utiliser la variable Median_Household_Income_2019
en log
sinon son échelle risque d’écraser tout effet.
Afficher les valeurs des coefficients, constante comprise
Evaluer la pertinence du modèle avec le \(R^2\) et la qualité du fit avec le MSE.
Représenter un nuage de points des valeurs observées et des erreurs de prédiction. Observez-vous un problème de spécification ?
Voici le nuage de points de nos erreurs:
Clairement, le modèle présente un problème de spécification.
Exercice 1b : Régression linéaire avec statsmodels
Cet exercice vise à illustrer la manière d’effectuer une régression linéaire avec statsmodels
qui offre des fonctionnalités plus proches de celles de R
, et moins orientées Machine Learning.
L’objectif est toujours d’expliquer le score des Républicains en fonction de quelques variables.
- A partir de quelques variables, par exemple, ‘Unemployment_rate_2019’, ‘Median_Household_Income_2019’, ‘Percent of adults with less than a high school diploma, 2015-19’, “Percent of adults with a bachelor’s degree or higher, 2015-19”, expliquer la variable
per_gop
. ⚠️ utiliser la variableMedian_Household_Income_2019
enlog
sinon son échelle risque d’écraser tout effet. - Afficher un tableau de régression.
- Evaluer la pertinence du modèle avec le R^2.
- Utiliser l’API
formula
pour régresser le score des républicains en fonction de la variableUnemployment_rate_2019
, deUnemployment_rate_2019
au carré et du log deMedian_Household_Income_2019
.
Hint
Pour sortir une belle table pour un rapport sous \(\LaTeX\), il est possible d’utiliser
la méthode Summary.as_latex
. Pour un rapport HTML, on utilisera Summary.as_html
Note
Les utilisateurs de R
retrouveront des éléments très familiers avec statsmodels
,
notamment la possibilité d’utiliser une formule pour définir une régression.
La philosophie de statsmodels
est similaire à celle qui a influé sur la construction
des packages stats
et MASS
de R
: offrir une librairie généraliste, proposant
une large gamme de modèles. Néanmoins, statsmodels
bénéficie de sa jeunesse
par rapport aux packages R
. Depuis les années 1990, les packages R
visant
à proposer des fonctionalités manquantes dans stats
et MASS
se sont
multipliés alors que statsmodels
, enfant des années 2010, n’a eu qu’à
proposer un cadre général (les generalized estimating equations) pour
englober ces modèles.
1.2 La régression logistique
Ce modèle s’applique à une distribution binaire. Dans ce cas, \(\mathbb{E}_{\theta} (Y|X) = \mathbb{P}_{\theta} (Y = 1|X)\). La régression logistique peut être vue comme un modèle linéaire en probabilité :
\[ \text{logit}\bigg(\mathbb{E}_{\theta}(Y|X)\bigg) = \text{logit}\bigg(\mathbb{P}_{\theta}(Y = 1|X)\bigg) = X\beta \]
La fonction \(\text{logit}\) est \(]0,1[ \to \mathbb{R}: p \mapsto \log(\frac{p}{1-p})\).
Elle permet ainsi de transformer une probabilité dans \(\mathbb{R}\). Sa fonction réciproque est la sigmoïde (\(\frac{1}{1 + e^{-x}}\)), objet central du Deep Learning.
Il convient de noter que les probabilités ne sont pas observées, c’est l’outcome binaire (0/1) qui l’est. Cela amène à voir la régression logistique de deux manières différentes :
- En économétrie, on s’intéresse au modèle latent qui détermine le choix de l’outcome. Par exemple, si on observe les choix de participer ou non au marché du travail, on va modéliser les facteurs déterminant ce choix ;
- En Machine Learning, le modèle latent n’est nécessaire que pour classifier dans la bonne catégorie les observations
L’estimation des paramètres \(\beta\) peut se faire par maximum de vraisemblance ou par régression, les deux solutions sont équivalentes sous certaines hypothèses.
Note
Par défaut, scikit
applique une régularisation pour pénaliser les modèles
peu parcimonieux (comportement différent
de celui de statsmodels
). Ce comportement par défaut est à garder à l’esprit
si l’objectif n’est pas de faire de la prédiction.
Exercice 2a : Régression logistique avec scikit
Avec scikit
, en utilisant échantillons d’apprentissage et d’estimation :
- Evaluer l’effet des variables déjà utilisées sur la probabilité des Républicains de gagner. Affichez la valeur des coefficients.
- Déduire une matrice de confusion et une mesure de qualité du modèle.
- Supprimer la régularisation grâce au paramètre
penalty
. Quel effet sur les paramètres estimés ?
Exercice 2b : Régression logistique avec statmodels
En utilisant échantillons d’apprentissage et d’estimation :
- Evaluer l’effet des variables déjà utilisées sur la probabilité des Républicains de gagner.
- Faire un test de ratio de vraisemblance concernant l’inclusion de la variable de (log)-revenu.
Hint
La statistique du test est : \[ LR = -2\log\bigg(\frac{\mathcal{L}_{\theta}}{\mathcal{L}_{\theta_0}}\bigg) = -2(\mathcal{l}_{\theta} - \mathcal{l}_{\theta_0}) \]
2 Pour aller plus loin
Ce chapitre n’évoque les enjeux de la régression que de manière très introductive. Pour compléter ceci, il est recommandé d’explorer les champs suivants:
- Les modèles linéaires généralisés pour découvrir la régression avec des hypothèses plus générales que celles que nous avons posées jusqu’à présent ;
- Les autres modèles de régression de machine learning comme les forêts aléatoires ;
- Les tests d’hypothèses pour aller plus loin sur ces questions que notre test de ratio de vraisemblance.
Informations additionnelles
environment files have been tested on.
Latest built version: 2024-10-12
Python version used:
'3.12.6 | packaged by conda-forge | (main, Sep 30 2024, 18:08:52) [GCC 13.3.0]'
Package | Version |
---|---|
affine | 2.4.0 |
aiobotocore | 2.15.1 |
aiohappyeyeballs | 2.4.3 |
aiohttp | 3.10.8 |
aioitertools | 0.12.0 |
aiosignal | 1.3.1 |
alembic | 1.13.3 |
altair | 5.4.1 |
aniso8601 | 9.0.1 |
annotated-types | 0.7.0 |
appdirs | 1.4.4 |
archspec | 0.2.3 |
asttokens | 2.4.1 |
attrs | 24.2.0 |
babel | 2.16.0 |
bcrypt | 4.2.0 |
beautifulsoup4 | 4.12.3 |
black | 24.8.0 |
blinker | 1.8.2 |
blis | 0.7.11 |
bokeh | 3.5.2 |
boltons | 24.0.0 |
boto3 | 1.35.23 |
botocore | 1.35.23 |
branca | 0.7.2 |
Brotli | 1.1.0 |
cachetools | 5.5.0 |
cartiflette | 0.0.2 |
Cartopy | 0.24.1 |
catalogue | 2.0.10 |
cattrs | 24.1.2 |
certifi | 2024.8.30 |
cffi | 1.17.1 |
charset-normalizer | 3.3.2 |
click | 8.1.7 |
click-plugins | 1.1.1 |
cligj | 0.7.2 |
cloudpathlib | 0.19.0 |
cloudpickle | 3.0.0 |
colorama | 0.4.6 |
comm | 0.2.2 |
commonmark | 0.9.1 |
conda | 24.9.1 |
conda-libmamba-solver | 24.7.0 |
conda-package-handling | 2.3.0 |
conda_package_streaming | 0.10.0 |
confection | 0.1.5 |
contextily | 1.6.2 |
contourpy | 1.3.0 |
cryptography | 43.0.1 |
cycler | 0.12.1 |
cymem | 2.0.8 |
cytoolz | 1.0.0 |
dask | 2024.9.1 |
dask-expr | 1.1.15 |
databricks-sdk | 0.33.0 |
debugpy | 1.8.6 |
decorator | 5.1.1 |
Deprecated | 1.2.14 |
diskcache | 5.6.3 |
distributed | 2024.9.1 |
distro | 1.9.0 |
docker | 7.1.0 |
duckdb | 0.10.1 |
en-core-web-sm | 3.7.1 |
entrypoints | 0.4 |
et-xmlfile | 1.1.0 |
exceptiongroup | 1.2.2 |
executing | 2.1.0 |
fastexcel | 0.11.6 |
fastjsonschema | 2.20.0 |
fiona | 1.10.1 |
Flask | 3.0.3 |
folium | 0.17.0 |
fontawesomefree | 6.6.0 |
fonttools | 4.54.1 |
frozendict | 2.4.4 |
frozenlist | 1.4.1 |
fsspec | 2023.12.2 |
funcy | 2.0 |
gensim | 4.3.2 |
geographiclib | 2.0 |
geopandas | 1.0.1 |
geoplot | 0.5.1 |
geopy | 2.4.1 |
gitdb | 4.0.11 |
GitPython | 3.1.43 |
google-auth | 2.35.0 |
graphene | 3.3 |
graphql-core | 3.2.4 |
graphql-relay | 3.2.0 |
graphviz | 0.20.3 |
great-tables | 0.12.0 |
greenlet | 3.1.1 |
gunicorn | 22.0.0 |
h2 | 4.1.0 |
hpack | 4.0.0 |
htmltools | 0.5.3 |
hyperframe | 6.0.1 |
idna | 3.10 |
imageio | 2.35.1 |
importlib_metadata | 8.5.0 |
importlib_resources | 6.4.5 |
inflate64 | 1.0.0 |
ipykernel | 6.29.5 |
ipython | 8.28.0 |
itsdangerous | 2.2.0 |
jedi | 0.19.1 |
Jinja2 | 3.1.4 |
jmespath | 1.0.1 |
joblib | 1.4.2 |
jsonpatch | 1.33 |
jsonpointer | 3.0.0 |
jsonschema | 4.23.0 |
jsonschema-specifications | 2024.10.1 |
jupyter-cache | 1.0.0 |
jupyter_client | 8.6.3 |
jupyter_core | 5.7.2 |
kaleido | 0.2.1 |
kiwisolver | 1.4.7 |
langcodes | 3.4.1 |
language_data | 1.2.0 |
lazy_loader | 0.4 |
libmambapy | 1.5.9 |
locket | 1.0.0 |
lxml | 5.3.0 |
lz4 | 4.3.3 |
Mako | 1.3.5 |
mamba | 1.5.9 |
mapclassify | 2.8.1 |
marisa-trie | 1.2.1 |
Markdown | 3.6 |
markdown-it-py | 3.0.0 |
MarkupSafe | 2.1.5 |
matplotlib | 3.9.2 |
matplotlib-inline | 0.1.7 |
mdurl | 0.1.2 |
menuinst | 2.1.2 |
mercantile | 1.2.1 |
mizani | 0.11.4 |
mlflow | 2.16.2 |
mlflow-skinny | 2.16.2 |
msgpack | 1.1.0 |
multidict | 6.1.0 |
multivolumefile | 0.2.3 |
munkres | 1.1.4 |
murmurhash | 1.0.10 |
mypy-extensions | 1.0.0 |
narwhals | 1.9.3 |
nbclient | 0.10.0 |
nbformat | 5.10.4 |
nest_asyncio | 1.6.0 |
networkx | 3.3 |
nltk | 3.9.1 |
numexpr | 2.10.1 |
numpy | 1.26.4 |
opencv-python-headless | 4.10.0.84 |
openpyxl | 3.1.5 |
opentelemetry-api | 1.16.0 |
opentelemetry-sdk | 1.16.0 |
opentelemetry-semantic-conventions | 0.37b0 |
OWSLib | 0.28.1 |
packaging | 24.1 |
pandas | 2.2.3 |
paramiko | 3.5.0 |
parso | 0.8.4 |
partd | 1.4.2 |
pathspec | 0.12.1 |
patsy | 0.5.6 |
Pebble | 5.0.7 |
pexpect | 4.9.0 |
pickleshare | 0.7.5 |
pillow | 10.4.0 |
pip | 24.2 |
platformdirs | 4.3.6 |
plotly | 5.24.1 |
plotnine | 0.13.6 |
pluggy | 1.5.0 |
polars | 1.8.2 |
preshed | 3.0.9 |
prometheus_client | 0.21.0 |
prometheus_flask_exporter | 0.23.1 |
prompt_toolkit | 3.0.48 |
protobuf | 4.25.3 |
psutil | 6.0.0 |
ptyprocess | 0.7.0 |
pure_eval | 0.2.3 |
py7zr | 0.20.8 |
pyarrow | 17.0.0 |
pyarrow-hotfix | 0.6 |
pyasn1 | 0.6.1 |
pyasn1_modules | 0.4.1 |
pybcj | 1.0.2 |
pycosat | 0.6.6 |
pycparser | 2.22 |
pycryptodomex | 3.21.0 |
pydantic | 2.9.2 |
pydantic_core | 2.23.4 |
Pygments | 2.18.0 |
pyLDAvis | 3.4.1 |
PyNaCl | 1.5.0 |
pynsee | 0.1.8 |
pyogrio | 0.10.0 |
pyOpenSSL | 24.2.1 |
pyparsing | 3.1.4 |
pyppmd | 1.1.0 |
pyproj | 3.7.0 |
pyshp | 2.3.1 |
PySocks | 1.7.1 |
python-dateutil | 2.9.0 |
python-dotenv | 1.0.1 |
python-magic | 0.4.27 |
pytz | 2024.1 |
pyu2f | 0.1.5 |
pywaffle | 1.1.1 |
PyYAML | 6.0.2 |
pyzmq | 26.2.0 |
pyzstd | 0.16.2 |
querystring_parser | 1.2.4 |
rasterio | 1.4.1 |
referencing | 0.35.1 |
regex | 2024.9.11 |
requests | 2.32.3 |
requests-cache | 1.2.1 |
retrying | 1.3.4 |
rich | 13.9.2 |
rpds-py | 0.20.0 |
rsa | 4.9 |
Rtree | 1.3.0 |
ruamel.yaml | 0.18.6 |
ruamel.yaml.clib | 0.2.8 |
s3fs | 2023.12.2 |
s3transfer | 0.10.2 |
scikit-image | 0.24.0 |
scikit-learn | 1.5.2 |
scipy | 1.13.0 |
seaborn | 0.13.2 |
setuptools | 74.1.2 |
shapely | 2.0.6 |
shellingham | 1.5.4 |
six | 1.16.0 |
smart-open | 7.0.5 |
smmap | 5.0.0 |
sortedcontainers | 2.4.0 |
soupsieve | 2.5 |
spacy | 3.7.5 |
spacy-legacy | 3.0.12 |
spacy-loggers | 1.0.5 |
SQLAlchemy | 2.0.35 |
sqlparse | 0.5.1 |
srsly | 2.4.8 |
stack-data | 0.6.2 |
statsmodels | 0.14.4 |
tabulate | 0.9.0 |
tblib | 3.0.0 |
tenacity | 9.0.0 |
texttable | 1.7.0 |
thinc | 8.2.5 |
threadpoolctl | 3.5.0 |
tifffile | 2024.9.20 |
toolz | 1.0.0 |
topojson | 1.9 |
tornado | 6.4.1 |
tqdm | 4.66.5 |
traitlets | 5.14.3 |
truststore | 0.9.2 |
typer | 0.12.5 |
typing_extensions | 4.12.2 |
tzdata | 2024.2 |
Unidecode | 1.3.8 |
url-normalize | 1.4.3 |
urllib3 | 1.26.20 |
wasabi | 1.1.3 |
wcwidth | 0.2.13 |
weasel | 0.4.1 |
webdriver-manager | 4.0.2 |
websocket-client | 1.8.0 |
Werkzeug | 3.0.4 |
wheel | 0.44.0 |
wordcloud | 1.9.3 |
wrapt | 1.16.0 |
xgboost | 2.1.1 |
xlrd | 2.0.1 |
xyzservices | 2024.9.0 |
yarl | 1.13.1 |
yellowbrick | 1.5 |
zict | 3.0.0 |
zipp | 3.20.2 |
zstandard | 0.23.0 |
View file history
SHA | Date | Author | Description |
---|---|---|---|
06d003a | 2024-04-23 10:09:22 | Lino Galiana | Continue la restructuration des sous-parties (#492) |
8c316d0 | 2024-04-05 19:00:59 | Lino Galiana | Fix cartiflette deprecated snippets (#487) |
005d89b | 2023-12-20 17:23:04 | Lino Galiana | Finalise l’affichage des statistiques Git (#478) |
7d12af8 | 2023-12-05 10:30:08 | linogaliana | Modularise la partie import pour l’avoir partout |
417fb66 | 2023-12-04 18:49:21 | Lino Galiana | Corrections partie ML (#468) |
a06a268 | 2023-11-23 18:23:28 | Antoine Palazzolo | 2ème relectures chapitres ML (#457) |
889a71b | 2023-11-10 11:40:51 | Antoine Palazzolo | Modification TP 3 (#443) |
154f09e | 2023-09-26 14:59:11 | Antoine Palazzolo | Des typos corrigées par Antoine (#411) |
9a4e226 | 2023-08-28 17:11:52 | Lino Galiana | Action to check URL still exist (#399) |
a8f90c2 | 2023-08-28 09:26:12 | Lino Galiana | Update featured paths (#396) |
3bdf3b0 | 2023-08-25 11:23:02 | Lino Galiana | Simplification de la structure 🤓 (#393) |
78ea2cb | 2023-07-20 20:27:31 | Lino Galiana | Change titles levels (#381) |
29ff3f5 | 2023-07-07 14:17:53 | linogaliana | description everywhere |
f21a24d | 2023-07-02 10:58:15 | Lino Galiana | Pipeline Quarto & Pages 🚀 (#365) |
58c7128 | 2023-06-11 21:32:03 | Lino Galiana | change na subset (#362) |
2ed4aa7 | 2022-11-07 15:57:31 | Lino Galiana | Reprise 2e partie ML + Règle problème mathjax (#319) |
f10815b | 2022-08-25 16:00:03 | Lino Galiana | Notebooks should now look more beautiful (#260) |
494a85a | 2022-08-05 14:49:56 | Lino Galiana | Images featured ✨ (#252) |
d201e3c | 2022-08-03 15:50:34 | Lino Galiana | Pimp la homepage ✨ (#249) |
12965ba | 2022-05-25 15:53:27 | Lino Galiana | :launch: Bascule vers quarto (#226) |
9c71d6e | 2022-03-08 10:34:26 | Lino Galiana | Plus d’éléments sur S3 (#218) |
c3bf4d4 | 2021-12-06 19:43:26 | Lino Galiana | Finalise debug partie ML (#190) |
fb14d40 | 2021-12-06 17:00:52 | Lino Galiana | Modifie l’import du script (#187) |
37ecfa3 | 2021-12-06 14:48:05 | Lino Galiana | Essaye nom différent (#186) |
5d0a5e3 | 2021-12-04 07:41:43 | Lino Galiana | MAJ URL script recup data (#184) |
5c10490 | 2021-12-03 17:44:08 | Lino Galiana | Relec @antuki partie modelisation (#183) |
2a8809f | 2021-10-27 12:05:34 | Lino Galiana | Simplification des hooks pour gagner en flexibilité et clarté (#166) |
2e4d586 | 2021-09-02 12:03:39 | Lino Galiana | Simplify badges generation (#130) |
4cdb759 | 2021-05-12 10:37:23 | Lino Galiana | :sparkles: :star2: Nouveau thème hugo :snake: :fire: (#105) |
7f9f97b | 2021-04-30 21:44:04 | Lino Galiana | 🐳 + 🐍 New workflow (docker 🐳) and new dataset for modelization (2020 🇺🇸 elections) (#99) |
59eadf5 | 2020-11-12 16:41:46 | Lino Galiana | Correction des typos partie ML (#81) |
347f50f | 2020-11-12 15:08:18 | Lino Galiana | Suite de la partie machine learning (#78) |
671f75a | 2020-10-21 15:15:24 | Lino Galiana | Introduction au Machine Learning (#72) |
Citation
@book{galiana2023,
author = {Galiana, Lino},
title = {Python pour la data science},
date = {2023},
url = {https://pythonds.linogaliana.fr/},
doi = {10.5281/zenodo.8229676},
langid = {fr}
}