Pour commencer, on télécharge les données des vins rouges et blancs du dépôt de UCI. Ces données sont tirées de :
P. Cortez, A. Cerdeira, F. Almeida, T. Matos and J. Reis. Modeling wine preferences by data mining from physicochemical properties. In Decision Support Systems, Elsevier, 47(4):547-553, 2009.
In [1]:
!wget https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv
In [2]:
!wget https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv
On utilise pandas pour explorer les données
In [1]:
import pandas
reds = pandas.read_csv('winequality-red.csv', sep=';')
reds.head(5)
Out[1]:
In [2]:
whites = pandas.read_csv('winequality-white.csv', sep=';')
whites.head(5)
Out[2]:
Voyons quelles sont les statistiques basiques pour ces vins :
In [3]:
wines = whites.append(reds)
print ('Il y a', len(wines), 'vins en tout (rouges + blancs)')
print ("Verifions qu'il y a bien", len(reds), '+', len(whites), 'vins en tout')
In [4]:
wines.describe()
Out[4]:
Comment est distribuée la valeur de qualité ?
In [5]:
wines.quality.value_counts()
Out[5]:
Quels vins ont obtenu la note maximum, c'est-à-dire 9 ?
In [12]:
wines[wines.quality == 9]
Out[12]:
In [6]:
%matplotlib inline
import matplotlib.pyplot as plt
Comment varie le pH parmi les vins ?
In [7]:
fig, ax = plt.subplots(figsize=(10, 5))
plt.plot(reds.index, reds.pH, 'ro')
ax.set_title('Vins vs pH')
ax.set_xlabel('Indice des vins')
_ = ax.set_ylabel('pH')
Regardons seulement les 10 premiers vins rouges
In [19]:
reds[0:10].pH.plot(kind='bar', title="Vins vs pH")
# whites[:50].chlorides.plot(kind='bar', title='Vins blancs et chlorides')
Out[19]:
In [25]:
_ = reds.sort_values('pH', ascending=False).pH[:25].plot(kind='bar')
Affichons la matrice de distribution de toutes les caractéristiques du vin rouge:
In [26]:
from pandas.tools.plotting import scatter_matrix
tmp = scatter_matrix(reds, alpha=0.2, figsize=(20,20))
Quelles propriétés distinguent les rouges des blancs ?
In [30]:
from pandas.plotting import parallel_coordinates
On ajoute une nouvelle colonne qui indique le type de vin et on fusionne tous les vins dans un dataframe. Nous ne garderons que quelques propriétés pour cette analyse.
In [28]:
reds['kind'] = 'red'
whites['kind'] = 'white'
wines = reds.append(whites)
sub_wines = wines[['alcohol', 'pH', 'density', 'chlorides', 'kind']]
On va maintenant afficher chaque vin comme une ligne traversant toutes les colonnes de propriétés, en coupant l'axe à la hauteur de sa valeur. Les blancs et les rouges sont représentés dans des couleurs différentes.
In [31]:
parallel_coordinates(sub_wines, 'kind', alpha=0.2, color=['y', 'r'])
Out[31]:
Le résultat est difficile à interpréter car les caractéristiques ne sont pas normalisées.
In [32]:
sub_wines = wines[['alcohol', 'pH', 'density', 'chlorides']]
sub_wines = (sub_wines - sub_wines.mean()) / (sub_wines.max() - sub_wines.min())
sub_wines['kind'] = wines['kind']
parallel_coordinates(sub_wines, 'kind', alpha=0.2, color=['y', 'r'])
Out[32]:
Les vins rouges et blancs semblent principalement différer par leur valeur de chloride.
Voyons si on peut entrainer un algorithme à reconnaître les vins rouges des vins blancs. On définit le vecteur d'entrée comme étant toutes les colonnes sauf la colonne 'kind' (qui contient la classe du vin).
In [33]:
from sklearn.linear_model import LogisticRegression
from sklearn.cross_validation import cross_val_score
X = wines.iloc[:, 0:-1]
X.head()
Out[33]:
La sortie attendue est la colonne 'kind', qui est le type du vin. Il faut la convertir pour que le vin rouge soit étiqueté 0 et le vin blanc 1.
In [34]:
y = wines.kind
y = y.apply(lambda val: 0 if val == 'white' else 1)
y.head()
Out[34]:
On crée un classifieur de type regression logistique. Voir http://scikit-learn.org/stable/modules/linear_model.html#logistic-regression pour plus de détails. Nous allons entraîner et évaluer 5 classifieurs sur 5 sous-ensembles des données, les explications sont sur http://scikit-learn.org/stable/modules/cross_validation.html#computing-cross-validated-metrics.
In [35]:
clf = LogisticRegression()
scores = cross_val_score(clf, X, y, cv=5)
print ("Accuracy: %0.2f%% (+/- %0.2f)" % (scores.mean()*100, scores.std() * 200))
Les caractéristiques ne sont pas normalisées, ce qui peut dégrader largement les performances des classifieurs. Voir http://scikit-learn.org/stable/modules/preprocessing.html. Nous allons prétraiter les données pour qu'elles aient une moyenne nulle et une variance unitaire. Les données prétraitées ne sont plus un dataFrame mais un numpy array (généralisation des matrices).
In [38]:
from sklearn.preprocessing import scale
X_std = scale(X)
X_std
Out[38]:
Entraînons et testons le classifieur avec les données normalisées:
In [39]:
scores_std = cross_val_score(clf, X_std, y, cv=5)
print ("Accuracy: %0.2f%% (+/- %0.2f)" % (scores_std.mean()*100, scores_std.std() * 200))
La normalisation a permis de gagner 1% sur la précision.
Ce notebook est adapté de Peter Parente, Data Science and IPython du meetup Tools of the Trade.