Commit c0fde792 authored by vincentvigon's avatar vincentvigon
Browse files

makov

parent 4e868d0f
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# Modèle linéaire généralisé (Generalize Linear Model) # Modèle linéaire généralisé (Generalize Linear Model)
***Introduction:*** Nous nous intéressons à la modélisation probabiste de données: Elles sont constituées d'input $x_i$ et d'ouput $y_i$. ***Introduction:*** Nous nous intéressons à la modélisation probabiste de données: Elles sont constituées d'input $x_i$ et d'ouput $y_i$.
* exemple 1: $y_i$ est le prix du $i$-ième appartement et $x_i$=(surface, ensoleillement, quatier) * exemple 1: $y_i$ est le prix du $i$-ième appartement et $x_i$=(surface, ensoleillement, quatier)
* exemple 2: $y_i$ est le nombre d'accident du $i$-ième client d'une assurance, et $x_i$ c'est toutes ses données personnelles. * exemple 2: $y_i$ est le nombre d'accident du $i$-ième client d'une assurance, et $x_i$ c'est toutes ses données personnelles.
On va chercher une loi de probabilité qui décrive au mieux la distribution (=la loi) d'un output lorsqu'on observe un input donné. Cette loi pourra dépendre d'un certain paramètre $w$ qu'il faudra ensuite ajuster au mieux. On va chercher une loi de probabilité qui décrive au mieux la distribution (=la loi) d'un output lorsqu'on observe un input donné. Cette loi pourra dépendre d'un certain paramètre $w$ qu'il faudra ensuite ajuster au mieux.
***Vocabulaire:*** ***Vocabulaire:***
* input = variable explicative = descripteur = variable exogène * input = variable explicative = descripteur = variable exogène
* output = variable réponse = variable cible = variable endogène * output = variable réponse = variable cible = variable endogène
***Mathématiquement 1:*** On imagine une fonction $L(x,y,w)$ et l'on décrète que la proba d'observer $y_i$ en présence de $x_i$ est: ***Mathématiquement 1:*** On imagine une fonction $L(x,y,w)$ et l'on décrète que la proba d'observer $y_i$ en présence de $x_i$ est:
$$ $$
L( x_i , y_i , w ) \qquad \qquad \hbox{ pour un certain } w L( x_i , y_i , w ) \qquad \qquad \hbox{ pour un certain } w
$$ $$
En supposant les observations indépendantes, la proba d'observer simultanément $y[0],y[1],y[2]...$ est donc de En supposant les observations indépendantes, la proba d'observer simultanément $y[0],y[1],y[2]...$ est donc de
$$ $$
L(x[0],y[0],w) * L(x[1],y[1],w) * L(x[2],y[2],w) * ... = \prod_i L( x_i , y_i , w ) L(x[0],y[0],w) * L(x[1],y[1],w) * L(x[2],y[2],w) * ... = \prod_i L( x_i , y_i , w )
$$ $$
Le meilleur $w$ possible, est naturellement celui qui rend le plus probable (=vraissemblable) nos données, à savoir: Le meilleur $w$ possible, est naturellement celui qui rend le plus probable (=vraissemblable) nos données, à savoir:
$$ $$
\hat w = \hbox{argmax}_w \prod_i L( x_i , y_i , w ) \hat w = \hbox{argmax}_w \prod_i L( x_i , y_i , w )
$$ $$
ce qu'on reformule souvent comme ceci: ce qu'on reformule souvent comme ceci:
$$ $$
\hat w = \hbox{argmin}_w - \sum_i \log L( x_i , y_i , w ) \hat w = \hbox{argmin}_w - \sum_i \log L( x_i , y_i , w )
$$ $$
Cette manière de choisir $w$ s'appelle: "la technique du maximum de vraissemblance". Cette manière de choisir $w$ s'appelle: "la technique du maximum de vraissemblance".
***Mathématiquement 2:*** L'explication précédente est simple, mais elle n'est rigoureuse que lorsque les données sont "discrètes" \[ex: $y_i$ est un nombre d'accident\]. Pour des variables continues \[ex: $y_i$ est le prix d'un appartement\], la probabilité d'observer exactement une donnée en particulier est nulle (en théorie). ***Mathématiquement 2:*** L'explication précédente est simple, mais elle n'est rigoureuse que lorsque les données sont "discrètes" \[ex: $y_i$ est un nombre d'accident\]. Pour des variables continues \[ex: $y_i$ est le prix d'un appartement\], la probabilité d'observer exactement une donnée en particulier est nulle (en théorie).
Reformulons notre méthodologie pour la rendre rigoureuse dans tous les cas: On imagine une fonction $L(x,y,w)$, et l'on décrète que les $y_i$ (petit y) sont des observations de v.a $Y_i$ (grand Y) dont la densité est: Reformulons notre méthodologie pour la rendre rigoureuse dans tous les cas: On imagine une fonction $L(x,y,w)$, et l'on décrète que les $y_i$ (petit y) sont des observations de v.a $Y_i$ (grand Y) dont la densité est:
$$ $$
y \to L(x_i,y,w) y \to L(x_i,y,w)
$$ $$
Ainsi la densité jointe de $Y_0,Y_1,Y_2...$ c'est Ainsi la densité jointe de $Y_0,Y_1,Y_2...$ c'est
$$ $$
\prod_i L( x_i , y_i , w ) \prod_i L( x_i , y_i , w )
$$ $$
et le paramètre qui rend le plus vraissemblable l'ensemble de nos données est toujours: et le paramètre qui rend le plus vraissemblable l'ensemble de nos données est toujours:
$$ $$
\hat w =\hbox{argmax}_w \prod_i L( x_i , y_i , w ) \hat w =\hbox{argmax}_w \prod_i L( x_i , y_i , w )
$$ $$
La seule différence c'est que la fonction $L$ peut dépasser 1. La seule différence c'est que la fonction $L$ peut dépasser 1.
***A quoi ça sert?*** A deux choses: ***A quoi ça sert?*** A deux choses:
1/ À comprendre l'influence de l'input $x$ sur l'output $y$. Ex: on pourra en déduire que le prix d'un appartement est une fonction affine de la surface, qu'il dépend exponentiellement de la 'chicosité' du quartier, mais aussi que, plus le quartier est chic, et plus la variance des prix augmente, etc. 1/ À comprendre l'influence de l'input $x$ sur l'output $y$. Ex: on pourra en déduire que le prix d'un appartement est une fonction affine de la surface, qu'il dépend exponentiellement de la 'chicosité' du quartier, mais aussi que, plus le quartier est chic, et plus la variance des prix augmente, etc.
2/ À prédire: supposons que l'on dispose d'un input $x'$ qui n'est pas dans nos données initiales; quel est l'output $y'$ qui lui correspondrait le mieux? ex: considérons un appartement $x'$=(surface: 33$m^2$, ensoleillement: sombre, quartier: très chic). Quelle est l'estimation de son prix?. Pour cela on peut prendre: 2/ À prédire: supposons que l'on dispose d'un input $x'$ qui n'est pas dans nos données initiales; quel est l'output $y'$ qui lui correspondrait le mieux? ex: considérons un appartement $x'$=(surface: 33$m^2$, ensoleillement: sombre, quartier: très chic). Quelle est l'estimation de son prix?. Pour cela on peut prendre:
* le $y'$ qui maximise la vraissemblance $y\to L(x',y,\hat w)$ * le $y'$ qui maximise la vraissemblance $y\to L(x',y,\hat w)$
* l'espérance de la v.a $Y$ dont la densité est $y\to L(x',y,\hat w)$ * l'espérance de la v.a $Y$ dont la densité est $y\to L(x',y,\hat w)$
On choisi en général la seconde estimation (qui coincide parfois avec la première). On choisi en général la seconde estimation (qui coincide parfois avec la première).
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
""" maintenant on va coder. On importe les libraires utiles.""" """ maintenant on va coder. On importe les libraires utiles."""
import numpy as np import numpy as np
import pandas as pd import pandas as pd
import statsmodels.api as sm import statsmodels.api as sm
from scipy import stats from scipy import stats
from matplotlib import pyplot as plt from matplotlib import pyplot as plt
np.set_printoptions(linewidth=50000,suppress=True,precision=2) np.set_printoptions(linewidth=50000,suppress=True,precision=2)
% matplotlib inline % matplotlib inline
``` ```
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# Comparaison de deux jeux de données # Comparaison de deux jeux de données
Observez les points ci-dessous. Observez les points ci-dessous.
* ressemblance: ils ont la même tendance : plus `x[i]` est grand, et plus `y[i]` est grand, et cette dépendance semble être linéaire. * ressemblance: ils ont la même tendance : plus `x[i]` est grand, et plus `y[i]` est grand, et cette dépendance semble être linéaire.
* dissemblance: sur le second, plus `x[i]` est grand, le plus la variabilité des `x[i]` est grande. De plus les `y[i]` sont tous positifs. * dissemblance: sur le second, plus `x[i]` est grand, le plus la variabilité des `x[i]` est grande. De plus les `y[i]` sont tous positifs.
On imagine bien qu'il ne faudra pas modéliser ces deux jeux de la même manière. On imagine bien qu'il ne faudra pas modéliser ces deux jeux de la même manière.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
x0=np.loadtxt("data/data0_x.csv") x0=np.loadtxt("data/data0_x.csv")
y0=np.loadtxt("data/data0_y.csv") y0=np.loadtxt("data/data0_y.csv")
x1=np.loadtxt("data/data1_x.csv") x1=np.loadtxt("data/data1_x.csv")
y1=np.loadtxt("data/data1_y.csv") y1=np.loadtxt("data/data1_y.csv")
plt.figure(figsize=(12,6)) plt.figure(figsize=(12,6))
plt.subplot(1,2,1) plt.subplot(1,2,1)
plt.plot(x0,y0,'.') plt.plot(x0,y0,'.')
plt.ylim([-20,100]) plt.ylim([-20,100])
plt.subplot(1,2,2) plt.subplot(1,2,2)
plt.plot(x1,y1,'.') plt.plot(x1,y1,'.')
plt.ylim([-20,100]); plt.ylim([-20,100]);
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
***Exo:*** En utilisant la technique des moindres carrés, calculer avec python la meilleur droite de régression pour ces deux jeux de données. Superposer cette droite avec les données. ***Exo:*** En utilisant la technique des moindres carrés, calculer avec python la meilleur droite de régression pour ces deux jeux de données. Superposer cette droite avec les données.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# Le modèle linéaire Gaussien # Le modèle linéaire Gaussien
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Considérons le premier jeu de données. Il est bien modélisé par une formule du type Considérons le premier jeu de données. Il est bien modélisé par une formule du type
y[i] = w0 + w1 x[i] + Bruit[i] y[i] = w0 + w1 x[i] + Bruit[i]
Si on suppose en plus que `Bruit[i]` c'est des v.a gaussiennes centrées de variance σ² (qui ne dépend pas de `i`), alors notre modèle est : Si on suppose en plus que `Bruit[i]` c'est des v.a gaussiennes centrées de variance σ² (qui ne dépend pas de `i`), alors notre modèle est :
y[i] ~ Normale (esp = μ[i] , var = σ² ), μ[i] = w0 + w1 x[i] y[i] ~ Normale (esp = μ[i] , var = σ² ), μ[i] = w0 + w1 x[i]
Remarque: Le second jeu de données serait mieux modélisé par des v.a de loi Gamma : elles sont positives, et leur variance augmente quand l'espérance augmente (quant le paramètre de forme est fixé). On verra cela plus tard. Remarque: Le second jeu de données serait mieux modélisé par des v.a de loi Gamma : elles sont positives, et leur variance augmente quand l'espérance augmente (quant le paramètre de forme est fixé). On verra cela plus tard.
Maintenant estimons les paramètres `w0` (=le biais) et `w1` (=la pente de la tendance) en utilisant la librairie `statsmodel` qui utilise la technique du maximum de vraissemblance. Maintenant estimons les paramètres `w0` (=le biais) et `w1` (=la pente de la tendance) en utilisant la librairie `statsmodel` qui utilise la technique du maximum de vraissemblance.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def estimate_linear_drift(x, y,verbose=False): def estimate_linear_drift(x, y,verbose=False):
""" on étend les descripteurs `x` en ajoutant une colonne de '1' . Car dans le modèle """ on étend les descripteurs `x` en ajoutant une colonne de '1' . Car dans le modèle
mu[i]= w0*'1' + w1*x[i] """ mu[i]= w0*'1' + w1*x[i] """
x_ext=np.stack([ np.ones(len(x)) , x],axis=1) x_ext=np.stack([ np.ones(len(x)) , x],axis=1)
model = sm.GLM(endog=y, exog=x_ext, family=sm.families.Gaussian()) model = sm.GLM(endog=y, exog=x_ext, family=sm.families.Gaussian())
model_results = model.fit() model_results = model.fit()
w=model_results.params w=model_results.params
if verbose: print(model_results.summary()) if verbose: print(model_results.summary())
return w return w
print("estimation de w0 w1:",estimate_linear_drift(x0, y0)); print("estimation de w0 w1:",estimate_linear_drift(x0, y0));
``` ```
%% Output %% Output
estimation de w0 w1: [ 4.63 9.75] estimation de w0 w1: [ 4.63 9.75]
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
""" traçons cette tendance """ """ traçons cette tendance """
w=estimate_linear_drift(x0, y0) w=estimate_linear_drift(x0, y0)
plt.plot(x0,y0,'.') plt.plot(x0,y0,'.')
xx=np.linspace(np.min(x0),np.max(x0),100) xx=np.linspace(np.min(x0),np.max(x0),100)
plt.plot(xx,w[0]+w[1]*xx); plt.plot(xx,w[0]+w[1]*xx);
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
***Exo:*** Calculez la vraissemblance $\prod_i L(x_i,y_i,w)$ dans le modèle gaussien. Ecrivez et simplifiez le problème de maximisation qui permet d'obtenir $\hat w$. Montrez qu'on retrouve la formule des moindres carrés. ***Exo:*** Calculez la vraissemblance $\prod_i L(x_i,y_i,w)$ dans le modèle gaussien. Ecrivez et simplifiez le problème de maximisation qui permet d'obtenir $\hat w$. Montrez qu'on retrouve la formule des moindres carrés.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Mais le fait d'avoir ajusté un modèle probabiliste sur les données nous permet de juger de la qualité de nos estiamtions. Observons le "summary" fourni par `statsmodel`: Mais le fait d'avoir ajusté un modèle probabiliste sur les données nous permet de juger de la qualité de nos estiamtions. Observons le "summary" fourni par `statsmodel`:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
estimate_linear_drift(x0, y0,verbose=True); estimate_linear_drift(x0, y0,verbose=True);
``` ```
%% Output %% Output
Generalized Linear Model Regression Results Generalized Linear Model Regression Results
============================================================================== ==============================================================================
Dep. Variable: y No. Observations: 1000 Dep. Variable: y No. Observations: 1000
Model: GLM Df Residuals: 998 Model: GLM Df Residuals: 998
Model Family: Gaussian Df Model: 1 Model Family: Gaussian Df Model: 1
Link Function: identity Scale: 90.9263687696 Link Function: identity Scale: 90.9263687696
Method: IRLS Log-Likelihood: -3673.0 Method: IRLS Log-Likelihood: -3673.0
Date: Wed, 06 Jun 2018 Deviance: 90745. Date: Wed, 06 Jun 2018 Deviance: 90745.
Time: 09:34:04 Pearson chi2: 9.07e+04 Time: 09:34:04 Pearson chi2: 9.07e+04
No. Iterations: 2 No. Iterations: 2
============================================================================== ==============================================================================
coef std err z P>|z| [0.025 0.975] coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
const 4.6305 0.613 7.557 0.000 3.430 5.832 const 4.6305 0.613 7.557 0.000 3.430 5.832
x1 9.7461 0.519 18.770 0.000 8.728 10.764 x1 9.7461 0.519 18.770 0.000 8.728 10.764
============================================================================== ==============================================================================
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Observons la ligne "const" ci dessus: Observons la ligne "const" ci dessus:
* `coef` c'est $\hat w_0$: le terme constant de notre droite de regression, qui approxime le "vrai" $w_0$. On l'appel aussi "biais" ou "intercept". * `coef` c'est $\hat w_0$: le terme constant de notre droite de regression, qui approxime le "vrai" $w_0$. On l'appel aussi "biais" ou "intercept".
* `std err` c'est l'écartype estimé de l'estimateur $\hat w_0$. * `std err` c'est l'écartype estimé de l'estimateur $\hat w_0$.
* `\[0.025 0.975\]` c'est l'intervalle de confiance à 95%. Le vrai paramètre $w_0$ appartient à cet intervalle avec une probabilité de 95%. * `\[0.025 0.975\]` c'est l'intervalle de confiance à 95%. Le vrai paramètre $w_0$ appartient à cet intervalle avec une probabilité de 95%.
* `P>|z|` c'est la p-value associé au test de nullité de $w_0$. Rappelons simplement la recette: * `P>|z|` c'est la p-value associé au test de nullité de $w_0$. Rappelons simplement la recette:
1/ On choisit un niveau de test, disons $\alpha=5\%$. 1/ On choisit un niveau de test, disons $\alpha=5\%$.
2/ Quand `p-value[j]`$<\alpha$, on choisi l'hypothèse H1 c.à.d qu'on décrète que `w[j]` est non-nul. 2/ Quand `p-value[j]`$<\alpha$, on choisi l'hypothèse H1 c.à.d qu'on décrète que `w[j]` est non-nul.
3/ Quand `p-value[j]`$>\alpha$, on choisi l'hypothèse H0 c.à.d qu'on décrète que `w[j]` est nul, donc les input `x[:,j]` n'ont pas d'influence sur l'output. On a toujours intérêt à enlever des inputs inutiles car ils parasitent l'interprétation des résultats. 3/ Quand `p-value[j]`$>\alpha$, on choisi l'hypothèse H0 c.à.d qu'on décrète que `w[j]` est nul, donc les input `x[:,j]` n'ont pas d'influence sur l'output. On a toujours intérêt à enlever des inputs inutiles car ils parasitent l'interprétation des résultats.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Résidus ### Résidus
Reprenons nos deux jeux de données. Reprenons nos deux jeux de données.
Les résidus ce sont les données `y[i]` moins l'estimation `mu[i]=b+w X[i]` (graphiquement :on soustrait aux points la droite de tendance). Quand le modèle linéaire gaussien est (approximativement) le bon, les résidus ont (approximativement) une distribution gaussienne. Les résidus ce sont les données `y[i]` moins l'estimation `mu[i]=b+w X[i]` (graphiquement :on soustrait aux points la droite de tendance). Quand le modèle linéaire gaussien est (approximativement) le bon, les résidus ont (approximativement) une distribution gaussienne.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
w0=estimate_linear_drift(x0, y0) w0=estimate_linear_drift(x0, y0)
w1=estimate_linear_drift(x1, y1) w1=estimate_linear_drift(x1, y1)
xx=np.linspace(np.min(x0),np.max(x0),100) xx=np.linspace(np.min(x0),np.max(x0),100)
plt.figure(figsize=(12,6)) plt.figure(figsize=(12,6))
plt.subplot(1,2,1) plt.subplot(1,2,1)
plt.plot(x0,y0,'.') plt.plot(x0,y0,'.')
plt.plot(xx,w0[0]+w0[1]*xx); plt.plot(xx,w0[0]+w0[1]*xx);
plt.ylim([-20,100]) plt.ylim([-20,100])
plt.subplot(1,2,2) plt.subplot(1,2,2)
plt.plot(x1,y1,'.') plt.plot(x1,y1,'.')
plt.plot(xx,w1[0]+w1[1]*xx); plt.plot(xx,w1[0]+w1[1]*xx);
plt.ylim([-20,100]); plt.ylim([-20,100]);
``` ```
%% Output %% Output
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def plot_residus(x,y): def plot_residus(x,y):
b,w=estimate_linear_drift(x, y) b,w=estimate_linear_drift(x, y)
residus= (y - b - w* x) residus= (y - b - w* x)
""" histogramme des résidus """ """ histogramme des résidus """
plt.hist(residus,bins=15,edgecolor="k",normed=True) plt.hist(residus,bins=15,edgecolor="k",normed=True)
""" on ajuste par dessus une courbe gaussienne. """ """ on ajuste par dessus une courbe gaussienne. """
xx=np.linspace(np.min(residus),np.max(residus),100) xx=np.linspace(np.min(residus),np.max(residus),100)
yy=stats.norm.pdf(xx,scale=np.std(residus)) yy=stats.norm.pdf(xx,scale=np.std(residus))
plt.plot(xx,yy) plt.plot(xx,yy)
plt.xlim(-50,50) plt.xlim(-50,50)
plt.ylim(0,0.1) plt.ylim(0,0.1)
plt.figure(figsize=(12,6)) plt.figure(figsize=(12,6))
plt.subplot(1,2,1) plt.subplot(1,2,1)
plot_residus(x0,y0) plot_residus(x0,y0)
plt.subplot(1,2,2) plt.subplot(1,2,2)
plot_residus(x1,y1) plot_residus(x1,y1)
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Pour le second jeu de donnée, l'hypothèse de résidu gaussien semble fausse. Pour aller au delà d'un test visuel, il existe des tests de gaussianité. Pour le second jeu de donnée, l'hypothèse de résidu gaussien semble fausse. Pour aller au delà d'un test visuel, il existe des tests de gaussianité.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# Modèle log-Gamma # Modèle log-Gamma
Observons un nouveau jeu de données : Observons un nouveau jeu de données :
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
x2=np.loadtxt("data/data2_x.csv") x2=np.loadtxt("data/data2_x.csv")
y2=np.loadtxt("data/data2_y.csv") y2=np.loadtxt("data/data2_y.csv")
plt.plot(x2,y2,'.'); plt.plot(x2,y2,'.');
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Il semble que les input `x[i]` ont un effet sur-linéaire sur les output `y[i]`. On pourrait alors imaginer que Il semble que les input `x[i]` ont un effet sur-linéaire sur les output `y[i]`. On pourrait alors imaginer que
Y[i] ~ Normale (esp = μ[i] , var = σ² ) avec μ[i]= exp(w0+ w1*X[i]) Y[i] ~ Normale (esp = μ[i] , var = σ² ) avec μ[i]= exp(w0+ w1*X[i])
Mais ce n'est encore une bonne modélisation: car sur les observations, plus `x[i]` est grand et plus la variance de `y[i]` est grande. De plus les données sont positives. Le choix naturel est alors: Mais ce n'est encore une bonne modélisation: car sur les observations, plus `x[i]` est grand et plus la variance de `y[i]` est grande. De plus les données sont positives. Le choix naturel est alors:
Y[i] ~ Gamma(shape = α, scale = μ[i]/ α) avec μ[i] = exp(w0+ w1*x[i] ) Y[i] ~ Gamma(shape = α, scale = μ[i]/ α) avec μ[i] = exp(w0+ w1*x[i] )
En effet, la loi gamma a deux paramètres `shape` et `scale`, et son espérance c'est le produit de ces deux paramètres. En effet, la loi gamma a deux paramètres `shape` et `scale`, et son espérance c'est le produit de ces deux paramètres.
***Vocabulaire et remarques:*** la fonction 'lien' est l'inverse de la fonction qui relie l'input à l'espérance des données modélisées. Donc ici la fonction 'lien' est le log. ***Vocabulaire et remarques:*** la fonction 'lien' est l'inverse de la fonction qui relie l'input à l'espérance des données modélisées. Donc ici la fonction 'lien' est le log.
Cherchez dans le code ci-dessous l'endroit où l'on précise cette fonction 'lien'. Remarquez aussi que l'on ne précise pas le paramètre de forme `α`: car il n'intervient pas dans la maximisation (tout comme la variance σ² dans le modèle linéaire). Cherchez dans le code ci-dessous l'endroit où l'on précise cette fonction 'lien'. Remarquez aussi que l'on ne précise pas le paramètre de forme `α`: car il n'intervient pas dans la maximisation (tout comme la variance σ² dans le modèle linéaire).
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
def estimate_exponential_drift(x, y): def estimate_exponential_drift(x, y):
x_ext=np.stack([ np.ones(len(x)) , x],axis=1) x_ext=np.stack([ np.ones(len(x)) , x],axis=1)
model = sm.GLM(endog=y, exog=x_ext, family=sm.families.Gamma(link=sm.families.links.log)) model = sm.GLM(endog=y, exog=x_ext, family=sm.families.Gamma(link=sm.families.links.log))
model_results = model.fit() model_results = model.fit()
w=model_results.params w=model_results.params
return w return w
w=estimate_exponential_drift(x2,y2) w=estimate_exponential_drift(x2,y2)
plt.plot(x2,y2,'.') plt.plot(x2,y2,'.')
xx=np.linspace(0,2,100) xx=np.linspace(0,2,100)
plt.plot(xx,np.exp(w[0]+w[1]*xx)); plt.plot(xx,np.exp(w[0]+w[1]*xx));
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
***Exo:*** La bibliothèque statsmodel a encore une fois utilisé la technique du maximum de vraissemblance. Ecrivez la vraissemblance $\prod_i L(x_i,y_i,w)$ en utilisant le fait que la densité de Gamma(shape = α, scale = 1) est : ***Exo:*** La bibliothèque statsmodel a encore une fois utilisé la technique du maximum de vraissemblance. Ecrivez la vraissemblance $\prod_i L(x_i,y_i,w)$ en utilisant le fait que la densité de Gamma(shape = α, scale = 1) est :
$$ $$
y \to \frac 1 {\Gamma(\alpha)} y ^{\alpha-1} e^{- y} y \to \frac 1 {\Gamma(\alpha)} y ^{\alpha-1} e^{- y}
$$ $$
(comme d'habitude, pour passer de scale = 1 à scale = θ on change y en y/θ et l'on multiplie la densité par 1/θ pour que l'intégrale reste égale à 1) (comme d'habitude, pour passer de scale = 1 à scale = θ on change y en y/θ et l'on multiplie la densité par 1/θ pour que l'intégrale reste égale à 1)
Ecrivez le problème de maximisation, simplifiez-le, vérifier que le paramètre de forme $\alpha$ n'intervient pas dans l'expression de $\hat w$. Ecrivez le problème de maximisation, simplifiez-le, vérifier que le paramètre de forme $\alpha$ n'intervient pas dans l'expression de $\hat w$.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# Modèle log-Poisson # Modèle log-Poisson
Observons de nouvelles données. L'output `y[i]` sont le nombre d'accident de l'individu `i`, l'input est `x[i]` est "l'indice fangio" de ce même individu. Observons de nouvelles données. L'output `y[i]` sont le nombre d'accident de l'individu `i`, l'input est `x[i]` est "l'indice fangio" de ce même individu.
Remarque: l'output est maintenant à valeur entière, mais cela reste une donnée quantitative. Remarque: l'output est maintenant à valeur entière, mais cela reste une donnée quantitative.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
x=np.loadtxt("data/accident_x.csv") x=np.loadtxt("data/accident_x.csv")
y=np.loadtxt("data/accident_y.csv") y=np.loadtxt("data/accident_y.csv")
plt.plot(x,y,'.'); plt.plot(x,y,'.');
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Les `y[i]` sont discrets. La majorité des individus ont 0 accident, mais ceux avec un grand indice fangio peuvent avoir de nombreux accidents, le reccord étant 7! On suppute que l'"indice fangio" a un effet multiplicatif sur la fréquence des accidents. Le modèle naturel est : Les `y[i]` sont discrets. La majorité des individus ont 0 accident, mais ceux avec un grand indice fangio peuvent avoir de nombreux accidents, le reccord étant 7! On suppute que l'"indice fangio" a un effet multiplicatif sur la fréquence des accidents. Le modèle naturel est :
Y[i] ~ Poisson (λ = μ[i]), avec μ[i]= exp(w0+ w1*X[i]) Y[i] ~ Poisson (λ = μ[i]), avec μ[i]= exp(w0+ w1*X[i])
On rappelle que l'espérance de la loi de Poisson, c'est son paramètre λ. On rappelle que l'espérance de la loi de Poisson, c'est son paramètre λ.
Nous utilisons `statsmodel` pour estimer les paramètres `w0` et `w1`. Pour le modèle Poissonien, la fonction de lien "par défaut" est la fonction log, donc nous n'avons pas besoin de la préciser dans le code ci-dessous. Nous utilisons `statsmodel` pour estimer les paramètres `w0` et `w1`. Pour le modèle Poissonien, la fonction de lien "par défaut" est la fonction log, donc nous n'avons pas besoin de la préciser dans le code ci-dessous.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
x_ext=sm.add_constant(x) x_ext=sm.add_constant(x)
model = sm.GLM(endog=y, exog=x_ext, family=sm.families.Poisson()) model = sm.GLM(endog=y, exog=x_ext, family=sm.families.Poisson())
res = model.fit() res = model.fit()
w=res.params w=res.params
print("estimation de w0 et w1:",w) print("estimation de w0 et w1:",w)
``` ```
%% Output %% Output
estimation de w0 et w1: [-4.02 5.03] estimation de w0 et w1: [-4.02 5.03]
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
plt.plot(x,y,'.') plt.plot(x,y,'.')
xx=np.linspace(0,1,100) xx=np.linspace(0,1,100)
plt.plot(xx,np.exp(w[0] + w[1]*xx ) ); plt.plot(xx,np.exp(w[0] + w[1]*xx ) );
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Modèle avec exposition ### Modèle avec exposition
Dans les données précédentes, le nombre d'accident était observer sur une période donnée commune à tous les clients (1 an). Dans les données précédentes, le nombre d'accident était observer sur une période donnée commune à tous les clients (1 an).
Dans les données suivantes, on observe les clients sur des durées variables. On a donc deux inputs: Dans les données suivantes, on observe les clients sur des durées variables. On a donc deux inputs:
1/ l'indice fangio 1/ l'indice fangio
2/ l'exposition (=la durée d'observation) qui est donnée en nombre de jour 2/ l'exposition (=la durée d'observation) qui est donnée en nombre de jour
On voit naturellement que plus la durée d'observation est longue, et plus le nombre d'accident est important. On voit naturellement que plus la durée d'observation est longue, et plus le nombre d'accident est important.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
xt=np.loadtxt("data/accident_exposure_x.csv") xt=np.loadtxt("data/accident_exposure_x.csv")
x=xt[:,0] #indice fangio x=xt[:,0] #indice fangio
t=xt[:,1] #exposition t=xt[:,1] #exposition
y=np.loadtxt("data/accident_exposure_y.csv") y=np.loadtxt("data/accident_exposure_y.csv")
plt.plot(t,y,'.'); plt.plot(t,y,'.');
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Il est donc naturelle de diviser le nombre d'accident par l'exposition. On obtient ainsi un nouvel output `y/t` que l'on peut essayer d'observer en fonction de l'indice fangio. On retombe alors sur un graphique similaire à celui du premier jeu de donnée d'accident. Il est donc naturelle de diviser le nombre d'accident par l'exposition. On obtient ainsi un nouvel output `y/t` que l'on peut essayer d'observer en fonction de l'indice fangio. On retombe alors sur un graphique similaire à celui du premier jeu de donnée d'accident.
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
plt.plot(x,y/t,'.'); plt.plot(x,y/t,'.');
``` ```
%% Output %% Output
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
On pourrait alors imaginer comme modèle: On pourrait alors imaginer comme modèle:
Y[i]/t[i] ~ Poisson (λ = μ[i]), avec μ[i]= exp(w0+ w1*X[i]) Y[i]/t[i] ~ Poisson (λ = μ[i]), avec μ[i]= exp(w0+ w1*X[i])
Mais ce n'est pas terrible (notamment car `Y/t` n'est pas un entier). Le bon modèle dans ce cas est: Mais ce n'est pas terrible (notamment car `Y/t` n'est pas un entier). Le bon modèle dans ce cas est:
Y[i] ~ Poisson (λ = μ[i]), avec μ[i]= t[i] exp(w0+ w1*X[i]) = exp(w0+ w1*X[i]+ log(t[i]) ) Y[i] ~ Poisson (λ = μ[i]), avec μ[i]= t[i] exp(w0+ w1*X[i]) = exp(w0+ w1*X[i]+ log(t[i]) )
On voit apparaire l'input `log(t[i])` dans l'exponentielle. C'est une variable dite "offset" car on ne cherche pas à lui associé un coefficient `w`. Observez comment on rajoute une variable offset dans `statsmodel` On voit apparaire l'input `log(t[i])` dans l'exponentielle. C'est une variable dite "offset" car on ne cherche pas à lui associé un coefficient `w`. Observez comment on rajoute une variable offset dans `statsmodel`
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
x_ext=sm.add_constant(x) x_ext=sm.add_constant(x)
model = sm.GLM(endog=y, exog=x_ext, family=sm.families.Poisson(),offset=np.log(t)) model = sm.GLM(endog=y, exog=x_ext, family=sm.families.Poisson(),offset=np.log(t))
res = model.fit() res = model.fit()
w=res.params w=res.params
print("estimation de w0 et w1:",w) print("estimation de w0 et w1:",w)
``` ```
%% Output %% Output
estimation de w0 et w1: [-10.04 5.17] estimation de w0 et w1: [-10.04 5.17]
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
***Exo:*** Les clients entre les deux jeux de données sont les mêmes. Dans le premier jeu, on avait simplement considéré des clients sur une période de 1 an. ***Exo:*** Les clients entre les deux jeux de données sont les mêmes. Dans le premier jeu, on avait simplement considéré des clients sur une période de 1 an.
Par un petit calcul, justifiez que l'intercep `w0` soit environ -4 dans le premier jeu et -10 dans le second jeu. Par un petit calcul, justifiez que l'intercep `w0` soit environ -4 dans le premier jeu et -10 dans le second jeu.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
# Modèle logistique pour la classification binaire # Modèle logistique pour la classification binaire
Les jeux de données vont maintenant changer de nature: la variable output sera une variable qualitative et non plus quantitative. On aura donc affaire à des problèmes de classification et non plus de régression. Les jeux de données vont maintenant changer de nature: la variable output sera une variable qualitative et non plus quantitative. On aura donc affaire à des problèmes de classification et non plus de régression.
Comme auparavant, on va essayer de trouver une bonne loi pour nos observations. Comme auparavant, on va essayer de trouver une bonne loi pour nos observations.
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### données individuelles ### données individuelles
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Dans le jeu de données suivant, chaque ligne représente une bactérie. Il y a 2 input (car `x` a 2 colonnes). Leur signification est: Dans le jeu de données suivant, chaque ligne représente une bactérie. Il y a 2 input (car `x` a 2 colonnes). Leur signification est:
* `x1[i]` : quantité de nouriture donnée à la bactérie `i` (en calories) * `x1[i]` : quantité de nouriture donnée à la bactérie `i` (en calories)
* `x2[i]` : quantité de d'oxigène donnée à la bactérie `i` (en litres) * `x2[i]` : quantité de d'oxigène donnée à la bactérie `i` (en litres)
L'output est binaire: L'output est binaire:
* `y[i]=0` : la bactérie `i` est morte * `y[i]=0` : la bactérie `i` est morte
* `y[i]=1` : la bactérie `i` est vivante * `y[i]=1` : la bactérie `i` est vivante
Observons les données: Observons les données:
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
x=np.loadtxt("data/bacteria_alone_x.csv") x=np.loadtxt("data/bacteria_alone_x.csv")
y=np.loadtxt("data/bacteria_alone_y.csv") y=np.loadtxt("data/bacteria_alone_y.csv")
print("matrice des inputs (transposée)") print("matrice des inputs (transposée)")
print(x[:10].T) print(x[:10].T)
print("vecteur des outputs") print("vecteur des outputs")
print(y[:10]) print(y[:10])
x_dead=x[y==0] x_dead=x[y==0]
x_alife=x[y==1] x_alife=x[y==1]
plt.plot(x_dead[:,0],x_dead[:,1],".",label="dead") plt.plot(x_dead[:,0],x_dead[:,1],".",label="dead")
plt.plot(x_alife[:,0],x_alife[:,1],".",label="alife") plt.plot(x_alife[:,0],x_alife[:,1],".",label="alife")
plt.legend(); plt.legend();
``` ```
%% Output %% Output
matrice des inputs (transposée) matrice des inputs (transposée)
[[ 2.7 0.69 2.09 2.03 0.67 3.74 2.61 4.08 2.85 3.18] [[ 2.7 0.69 2.09 2.03 0.67 3.74 2.61 4.08 2.85 3.18]
[ 2.54 4.54 4.1 1.86 3.21 1.76 1.87 3.36 0.62 0.82]] [ 2.54 4.54 4.1 1.86 3.21 1.76 1.87 3.36 0.62 0.82]]
vecteur des outputs vecteur des outputs
[ 1. 0. 1. 0. 0. 1. 0. 1. 0. 1.] [ 1. 0. 1. 0. 0. 1. 0. 1. 0. 1.]
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
Nous aimerions connaître l'effet des inputs sur la probabilité de survie des bactéries. Nous supposons alors que l'output a la loi suivante : Nous aimerions connaître l'effet des inputs sur la probabilité de survie des bactéries. Nous supposons alors que l'output a la loi suivante :
Y[i] ~ Bernoulli(p = μ[i] ), μ[i] = sigmoid(w . x[i]) Y[i] ~ Bernoulli(p = μ[i] ), μ[i] = sigmoid(w . x[i])
avec avec
* `sigmoid(t) = exp(t) / (1 + exp(t))` est une fonction croissante qui a le bon goût d'arriver dans \[0,1\], ce qui fournit donc une probabilité. * `sigmoid(t) = exp(t) / (1 + exp(t))` est une fonction croissante qui a le bon goût d'arriver dans \[0,1\], ce qui fournit donc une probabilité.
* `w =(w[0],w[1],w[2])` est un vecteur de 3 paramètres. Le premier paramètre `w[0]`est le biais (='intercept') * `w =(w[0],w[1],w[2])` est un vecteur de 3 paramètres. Le premier paramètre `w[0]`est le biais (='intercept')
* `w . x[i]` est le produit scalaire entre `w` et la i-ième ligne de l'input `x`. Attention, il s'agit de l'input étendu `x[i,:]=(1,x1[i],x2[i])` * `w . x[i]` est le produit scalaire entre `w` et la i-ième ligne de l'input `x`. Attention, il s'agit de l'input étendu `x[i,:]=(1,x1[i],x2[i])`
%% Cell type:code id: tags: %% Cell type:code id: tags:
``` python ``` python
""" on ajoute une colonne de 1 (on pourrait aussi utiliser np.concatenate)""" """ on ajoute une colonne de 1 (on pourrait aussi utiliser np.concatenate)"""
x=sm.add_constant(x) x=sm.add_constant(x)
glm = sm.GLM(endog=y, exog=x, family=sm.families.Binomial()) glm = sm.GLM(endog=y, exog=x, family=sm.families.Binomial())
res = glm.fit() res = glm.fit()
res.summary() res.summary()
``` ```
%% Output %% Output
<class 'statsmodels.iolib.summary.Summary'> <class 'statsmodels.iolib.summary.Summary'>
""" """
Generalized Linear Model Regression Results Generalized Linear Model Regression Results
============================================================================== ==============================================================================
Dep. Variable: y No. Observations: 1000 Dep. Variable: y No. Observations: 1000
Model: GLM Df Residuals: 997 Model: GLM Df Residuals: 997
Model Family: Binomial Df Model: 2 Model Family: Binomial Df Model: 2
Link Function: logit Scale: 1.0 Link Function: logit Scale: 1.0
Method: IRLS Log-Likelihood: -170.81 Method: IRLS Log-Likelihood: -170.81
Date: Wed, 06 Jun 2018 Deviance: 341.63 Date: Wed, 06 Jun 2018 Deviance: 341.63
Time: 09:34:09 Pearson chi2: 889. Time: 09:34:09 Pearson chi2: 889.
No. Iterations: 8 No. Iterations: 8
============================================================================== ==============================================================================
coef std err z P>|z| [0.025 0.975] coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
const -14.2051 1.106 -12.845 0.000 -16.373 -12.038 const -14.2051 1.106 -12.845 0.000 -16.373 -12.038
x1 3.6980 0.285 12.981 0.000 3.140 4.256 x1 3.6980 0.285 12.981 0.000 3.140 4.256
x2 2.0054 0.177 11.314 0.000 1.658 2.353 x2 2.0054 0.177 11.314 0.000 1.658 2.353
============================================================================== ==============================================================================
""" """
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
`statmodel` nous indique que les paramètres qui maximisent la vraisemblance des données sont approximativement: `statmodel` nous indique que les paramètres qui maximisent la vraisemblance des données sont approximativement:
w = [-14.2,3.6,2.0] w = [-14.2,3.6,2.0]
***Exo:*** supposons que l'on ait une bactérie que l'on a nourrit avec 3 callories et 0.5 littre d'oxigène. Quelle est sa probabilité de survie? ***Exo:*** supposons que l'on ait une bactérie que l'on a nourrit avec 3 callories et 0.5 littre d'oxigène. Quelle est sa probabilité de survie?
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
*** A vous:*** *** A vous:***
Découpez le jeu de données en 2 parties. Une partie `train` (800 lignes) et une partie `test` (200 lignes). Vous obtiendrez ainsi 2 matrices `x_test` et `x_train` et 2 vecteurs `y_test` et `y_train` Découpez le jeu de données en 2 parties. Une partie `train` (800 lignes) et une partie `test` (200 lignes). Vous obtiendrez ainsi 2 matrices `x_test` et `x_train` et 2 vecteurs `y_test` et `y_train`
Estimez `w` à partir du jeu train. Puis pour chaque élément du jeu `test` estimez une probabilité de survie `hat_y_test_proba`. Calculez: Estimez `w` à partir du jeu train. Puis pour chaque élément du jeu `test` estimez une probabilité de survie `hat_y_test_proba`. Calculez:
hat_y_test = (hat_y_test_proba>0.5) hat_y_test = (hat_y_test_proba>0.5)
comparez `hat_y_test` et `y_test` comparez `hat_y_test` et `y_test`
%% Cell type:markdown id: tags: %% Cell type:markdown id: tags:
### Données groupées ### Données groupées
Dans le jeu de données suivant, chaque ligne représente un lot bactérie. Les inputs ont la même signification: quantité de nourriture, quantité d'oxygène (par bactérie). Mais maintenant la sortie comporte deux colonnes: Dans le jeu de données suivant, chaque ligne représente un lot bactérie. Les inputs ont la même signification: quantité de nourriture, quantité d'oxygène (par bactérie). Mais maintenant la sortie comporte deux colonnes:
* `y[i,0]` : nombre de bactérie vivante dans le lot `i` * `y[i,0]` : nombre de bactérie vivante dans le lot `i`
* `y[i,1]` : nombre de bactérie morte dans le lot `i` * `y[i,1]` : nombre de bactérie morte dans