Introduction à la Recherche Opérationelle


M2 Statistique Science des Données (SSD)
Anatoli Juditsky
Franck Iutzeler
Version Py2019

Problème de régression logistique

Dans cet TP, nous cherchons à classer des observations en deux classes: $\mathcal{O} = \{-1 , +1 \}$ par régression logistique. La fonction de perte logistique s'écrit \begin{align*} \min_{x\in\mathbb{R}^d } f(x) := \frac{1}{m} \sum_{i=1}^m \log( 1+\exp(-b_i \langle a_i,x \rangle) ) + \lambda_1 \|x\|_1 + \frac{\lambda}{2} \|x\|_2^2. \end{align*} où:

  • $a_i$ est une observation et $b_i$ la classe correspondate
  • les deux derniers termes s'écrivent sont une régularisation de type elastic-net.

Sous certaines hypothèses évoquées ici, $x^\star = \arg\min f(x)$ maximise la vraisemblance régularisées des labels sachant les observations. Ainsi pour une nouvelle observation $a$ de classe $d$ (inconnue), $$ p_1(a) = \mathbb{P}[d\in \text{ class } +1] = \frac{1}{1+\exp(-\langle a;x^\star \rangle)} $$

Ainsi, a partir de $a$, si $p_1(a)$ est proche de $1$, il est raisonnable de décider que l'example arrivant appartient à la classe $1$; et l'inverse si $p(a)$ est proche de $0$. Entre les deux, l'appréciation est laissée à l'analyste selon l'application.

Vos objectifs:

  • Implementer une fonction de minimisation de la perte logistique régularisée en utilisant CVXR
  • Écrire une fonction de prédiction des labels pour un nouveau vecteur à partir de la solution obtenue par la fonction précédente
  • Motivez un choix pour les paramètres du modèle ($\lambda_1, \lambda_2$) et de la prédiction (seuil entre +1 et -1)

Rendu: Par groupe de 1,2, ou 3, un compte rendu d'une page + le code des deux fonctions demandées:

Données

Les données Student database contient les notes d'élèves portugais en mathématiques niveau lycée en fonction de facteurs socio-culturels. Le but est de prédire si un étudiant va passer dans la classe supérieure , note G3 supérieure ou égale à 12 grace à la donnée du reste.

La description des variables sont dans data/student.txt, la plupart sont catégoriques, vous les pré-traiterez pour les rendre numériques.

In [1]:
import pandas as pd
import numpy as np
In [2]:
data = pd.read_csv("./data/student-mat.csv",sep=";")
In [3]:
data
Out[3]:
school sex age address famsize Pstatus Medu Fedu Mjob Fjob ... famrel freetime goout Dalc Walc health absences G1 G2 G3
0 GP F 18 U GT3 A 4 4 at_home teacher ... 4 3 4 1 1 3 6 5 6 6
1 GP F 17 U GT3 T 1 1 at_home other ... 5 3 3 1 1 3 4 5 5 6
2 GP F 15 U LE3 T 1 1 at_home other ... 4 3 2 2 3 3 10 7 8 10
3 GP F 15 U GT3 T 4 2 health services ... 3 2 2 1 1 5 2 15 14 15
4 GP F 16 U GT3 T 3 3 other other ... 4 3 2 1 2 5 4 6 10 10
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
390 MS M 20 U LE3 A 2 2 services services ... 5 5 4 4 5 4 11 9 9 9
391 MS M 17 U LE3 T 3 1 services services ... 2 4 5 3 4 2 3 14 16 16
392 MS M 21 R GT3 T 1 1 other other ... 5 5 3 3 3 3 3 10 8 7
393 MS M 18 R LE3 T 3 2 services other ... 4 4 1 3 4 5 0 11 12 10
394 MS M 19 U LE3 T 1 1 other at_home ... 3 2 3 3 3 5 5 8 9 9

395 rows × 33 columns

In [4]:
from sklearn import preprocessing

le = preprocessing.LabelEncoder()

toencode = ["school","sex","address","famsize","Pstatus","Mjob","Fjob","reason","guardian","schoolsup","famsup","paid","activities","nursery","higher","internet","romantic"]
In [5]:
data[toencode] = data[toencode].apply(le.fit_transform) 
In [6]:
data
Out[6]:
school sex age address famsize Pstatus Medu Fedu Mjob Fjob ... famrel freetime goout Dalc Walc health absences G1 G2 G3
0 0 0 18 1 0 0 4 4 0 4 ... 4 3 4 1 1 3 6 5 6 6
1 0 0 17 1 0 1 1 1 0 2 ... 5 3 3 1 1 3 4 5 5 6
2 0 0 15 1 1 1 1 1 0 2 ... 4 3 2 2 3 3 10 7 8 10
3 0 0 15 1 0 1 4 2 1 3 ... 3 2 2 1 1 5 2 15 14 15
4 0 0 16 1 0 1 3 3 2 2 ... 4 3 2 1 2 5 4 6 10 10
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
390 1 1 20 1 1 0 2 2 3 3 ... 5 5 4 4 5 4 11 9 9 9
391 1 1 17 1 1 1 3 1 3 3 ... 2 4 5 3 4 2 3 14 16 16
392 1 1 21 0 0 1 1 1 2 2 ... 5 5 3 3 3 3 3 10 8 7
393 1 1 18 0 1 1 3 2 3 2 ... 4 4 1 3 4 5 0 11 12 10
394 1 1 19 1 1 1 1 1 2 0 ... 3 2 3 3 3 5 5 8 9 9

395 rows × 33 columns

A vous de jouer

In [7]:
import cvxpy as cp
In [ ]: