Découpage stratifié apprentissage / test¶
Lorsqu’une classe est sous-représentée, il y a peu de chances que la répartition apprentissage test conserve la distribution des classes.
[1]:
%matplotlib inline
[1]:
from teachpyx.datasets import load_wines_dataset
df = load_wines_dataset()
X = df.drop(["quality", "color"], axis=1)
y = df["quality"]
On divise en base d’apprentissage et de test avec la fonction train_test_split.
[2]:
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y)
[4]:
import pandas
ys = pandas.DataFrame(dict(y=y_train))
ys["base"] = "train"
ys2 = pandas.DataFrame(dict(y=y_test))
ys2["base"] = "test"
ys = pandas.concat([ys, ys2])
ys["compte"] = 1
piv = (
ys.groupby(["base", "y"], as_index=False)
.count()
.pivot(index="y", columns="base", values="compte")
)
piv["ratio"] = piv["test"] / piv["train"]
piv
[4]:
base | test | train | ratio |
---|---|---|---|
y | |||
3 | 9 | 21 | 0.428571 |
4 | 45 | 171 | 0.263158 |
5 | 553 | 1585 | 0.348896 |
6 | 702 | 2134 | 0.328960 |
7 | 261 | 818 | 0.319071 |
8 | 51 | 142 | 0.359155 |
9 | 4 | 1 | 4.000000 |
On voit le ratio entre les deux classes est à peu près égal à 1/3 sauf pour les notes sous-représentées. On utilise une répartition stratifiée : la distribution d’une variable, les labels, sera la même dans les bases d’apprentissages et de de tests. On s’inspire de l’exemple StratifiedShuffleSplit.
[5]:
from sklearn.model_selection import StratifiedShuffleSplit
split = StratifiedShuffleSplit(n_splits=1, test_size=0.33)
train_index, test_index = list(split.split(X, y))[0]
len(train_index), len(test_index)
[5]:
(4352, 2145)
[6]:
X_train, y_train = X.iloc[train_index, :], y[train_index]
X_test, y_test = X.iloc[test_index, :], y[test_index]
y_train.shape, y_test.shape
[6]:
((4352,), (2145,))
[8]:
ys = pandas.DataFrame(dict(y=y_train))
ys["base"] = "train"
ys2 = pandas.DataFrame(dict(y=y_test))
ys2["base"] = "test"
ys = pandas.concat([ys, ys2])
ys["compte"] = 1
piv = (
ys.groupby(["base", "y"], as_index=False)
.count()
.pivot(index="y", columns="base", values="compte")
)
piv["ratio"] = piv["test"] / piv["train"]
piv
[8]:
base | test | train | ratio |
---|---|---|---|
y | |||
3 | 10 | 20 | 0.500000 |
4 | 71 | 145 | 0.489655 |
5 | 706 | 1432 | 0.493017 |
6 | 936 | 1900 | 0.492632 |
7 | 356 | 723 | 0.492393 |
8 | 64 | 129 | 0.496124 |
9 | 2 | 3 | 0.666667 |
Le ratio entre les classes est identique, la classe test contient deux fois moins d’invidivu et c’est vrai pour toutes les classes excepté pour la classe 9 qui contient si peu d’éléments que c’est impossible.
[9]:
from sklearn.neighbors import KNeighborsRegressor
knn = KNeighborsRegressor(n_neighbors=1)
knn.fit(X_train, y_train)
[9]:
KNeighborsRegressor(n_neighbors=1)In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
KNeighborsRegressor(n_neighbors=1)
[10]:
prediction = knn.predict(X_test)
[11]:
from sklearn.metrics import r2_score
r2_score(y_test, prediction)
[11]:
-0.15256811411591387
Cela n’améliore pas la qualité du modèle mais on est sûr que les classes sous-représentées sont mieux gérées par cette répartition aléatoire stratifiée.