Inspiré par l'exellent livre de Sebastian Raschka (@rasbt) : Python Machine learning et Notebook ainsi que par les tuto de Scikit Learn sur Kaggle
In [1]:
import pandas as pd
import numpy as np
import seaborn as sns
#sns.set_style('whitegrid')
import matplotlib.pyplot as plt
%matplotlib inline
import warnings
warnings.simplefilter('ignore', DeprecationWarning)
Graphiques représentant le nombre de retraité et le nombre de vote FN par ville durant le second tour des elections régionales (lien github).
On observe une meilleure distribution des données si celle-ci sont transformées
In [2]:
df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data', header=None)
df.columns = ["label", "Alcohol", "Malic acid", "Ash", "Alcalinity of ash", "Magnesium", "Total phenols", "Flavanoids",
"Nonflavanoid phenols", "Proanthocyanins", "Color intensity", "Hue", "OD280/OD315 of diluted wines",
"Proline"]
df.head()
Out[2]:
In [3]:
df[['Alcohol', 'Malic acid']].describe()
Out[3]:
La feature "Alcohol" (%/vol) et "Malic acid" (g/l) n'ont pas les mêmes échelles. On compare donc des choux et des carottes...
In [4]:
sns.lmplot(x="Alcohol", y="Malic acid", hue="label", data=df, fit_reg=False, markers=['^', 's', 'o'])
Out[4]:
In [5]:
# On normalise les features
from sklearn.preprocessing import StandardScaler
df_scale = df.copy()
for col in df_scale.columns[1:]:
scaler = StandardScaler()
df_scale[col] = scaler.fit_transform(df_scale[col])
In [6]:
df_scale[['Alcohol', 'Malic acid']].describe()
Out[6]:
"alcool" et "acide malique" ont maintenant une moyenne de 0 et un std de 1
In [ ]:
sns.lmplot(x="Alcohol", y="Malic acid", hue="label", data=df_scale, fit_reg=False, markers=['^', 's', 'o'])
La normalisation est crucial lors d'un PCA (Principal Component Analysis), observons la différence à l'aide d'un graphique :
In [ ]:
# Using PCA
from sklearn.decomposition import PCA
# X = features, y = label
X, y = df.iloc[:, 1:].values, df.iloc[:,0].values # No scale
X_scale, y = df_scale.iloc[:, 1:].values, df_scale.iloc[:,0].values #scale
# non scale
pca = PCA(n_components=2).fit(X)
data_pca = pca.transform(X)
pca_df = pd.DataFrame(data_pca, columns=['pca_1', 'pca_2'])
pca_df['label'] = df['label']
# scale
pca_scale = PCA(n_components=2).fit(X_scale)
data_pca_scale = pca_scale.transform(X_scale)
pca_scale_df = pd.DataFrame(data_pca_scale, columns=['pca_1', 'pca_2'])
pca_scale_df['label'] = df['label']
In [ ]:
In [ ]:
pca_df.head()
In [ ]:
g=sns.lmplot(x="pca_1", y="pca_2", hue="label", data=pca_df, fit_reg=False, markers=['^', 's', 'o'])
In [ ]:
sns.lmplot(x="pca_1", y="pca_2", hue="label", data=pca_scale_df, fit_reg=False, markers=['^', 's', 'o'])
Dans la verion "PCA normalisé", on retrouve nos 3 clusters assez délimités alors que pour la version "PCA non normalisé", la délimitation est beaucoup chaotique.
Les features contenant du texte doivent etre transformées afin de nourir l'algorithme par la suite.
In [7]:
import pandas as pd
df = pd.DataFrame([
['green', 'M', 10.1, 'class1'],
['red', 'L', 13.5, 'class2'],
['blue', 'XL', 15.3, 'class1']])
df.columns = ['color', 'size', 'prize', 'class label']
df
Out[7]:
In [8]:
from sklearn.preprocessing import LabelEncoder
LE = LabelEncoder()
df['class label'] = LE.fit_transform(df['class label'])
In [9]:
df
Out[9]:
Ensuite se pose la question pour "color" et "size" :
- "size": Il y a un ordre de grandeur. Il faut donc respecter cette ordre de grandeur avec notre transformation.
- "color": Suivant le type d'algorythme utilisé, on peux la transformé comme "class label" ou bien la "binariser", c'est à dire que chaque valeur possible sera une colonne (avec des 0 ou 1)
In [10]:
size_mapping = {
'XL': 3,
'L': 2,
'M': 1}
df['size'] = df['size'].map(size_mapping)
df
Out[10]:
In [11]:
pd.get_dummies(df)
Out[11]:
Pour le challenge Rossman, la metric est le Root Mean Square Percentage Error (RMSPE). Compréhension par l'exemple :
In [12]:
# To compute RMSPE
def ToWeight(y):
w = np.zeros(y.shape, dtype=float)
ind = y != 0
w[ind] = 1./(y[ind]**2)
return w
def RMSPE(y, yhat):
w = ToWeight(y)
rmspe = np.sqrt(np.mean( w * (y - yhat)**2 ))
return rmspe
In [13]:
real_value = np.array([3500, 6400, 5000]) # Les valeurs que je cherche à prédire
prediction_1 = np.array([3000, 5900, 5500]) # assez bonne
prediction_2 = np.array([2510, 4000, 8000]) # pas terrible
prediction_3 = np.array([3400, 6490, 5070]) # exellente
In [14]:
print "1 - Prédiction assez bonne : %s" %(RMSPE(prediction_1, real_value))
print "2 - Mauvaise prédiction : %s" %(RMSPE(prediction_2, real_value))
print "3 - Bonne prédiction : %s" %(RMSPE(prediction_3, real_value))
Pour le challenge Homesite, la metric est Area under the curve (AUC), elle permet d'étudier la performance d’un classifieur binaire. Elle va de 0 à 1 (1 étant un classicateur parfait)
In [15]:
from sklearn.metrics import roc_auc_score, roc_curve, auc
In [16]:
real_value = np.array([0, 0, 1, 1]) # Les valeurs que je cherche à prédire
prediction_1 = np.array([0.1, 0.4, 0.3, 0.8]) # assez bonne
prediction_2 = np.array([0.55, 0.4, 0.48, 0.35]) # pas terrible
prediction_3 = np.array([0.1, 0.2, 0.8, 0.9]) # exellente
In [17]:
print "1 - Prédiction assez bonne : %s" %(roc_auc_score(real_value, prediction_1))
print "2 - Mauvaise prédiction : %s" %(roc_auc_score(real_value, prediction_2))
print "3 - Bonne prédiction : %s" %(roc_auc_score(real_value, prediction_3))
Pour aller plus loin graphiquement. N'hésitez pas à modifier les valeurs de "real_value" et des prédiction. Attention "real_value" doit avoir le même nombre de valeurs que les prédictions.
In [18]:
def plot_roc(true_positive_rate, false_positive_rate, roc_auc, title=''):
"""
To plot ROC curve
"""
title = 'Receiver Operating Characteristic' + title
plt.title(title)
plt.plot(false_positive_rate, true_positive_rate, 'b',
label='AUC = %0.2f'% roc_auc)
plt.legend(loc='lower right')
plt.plot([0,1],[0,1],'r--')
plt.xlim([-0.1,1.2])
plt.ylim([-0.1,1.2])
plt.ylabel('True Positive Rate')
plt.xlabel('False Positive Rate')
plt.show()
In [19]:
# List of all my predicitons
my_list_pred = [prediction_1, prediction_2, prediction_3]
my_predictions = []
for pred in my_list_pred:
my_predictions.append(pred)
In [20]:
# Plot ROC
i = 1
for prediction in my_predictions:
false_positive_rate, true_positive_rate, thresholds = roc_curve(real_value, prediction)
roc_auc = auc(false_positive_rate, true_positive_rate)
plot_roc(true_positive_rate, false_positive_rate, roc_auc, title='_'+str(i))
i += 1
In [56]:
from sklearn.datasets import load_iris
# Get data
iris = load_iris()
# create X (features) and y (target)
X = iris.data
y = iris.target
print "Il y %d de lignes pour X" %(len(X))
print "Il y %d de lignes pour y" %(len(y))
X[0:5]
Out[56]:
In [73]:
from sklearn.cross_validation import train_test_split
# Split le dataset en train (apprentissage) et test (phase de validation)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25,
random_state=4) # Hésitez pas à changer le random split
print "Il y %d de lignes pour X_train" %(len(X_train))
print "Il y %d de lignes pour y_train" %(len(y_train))
print "Il y %d de lignes pour X_test" %(len(X_test))
print "Il y %d de lignes pour y_test" %(len(y_test))
In [74]:
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train, y_train) # On entraine le modèle (sur train)
y_pred = knn.predict(X_test) # On prédit le résultat sur un partie de données inconnu (test)
print accuracy_score(y_test, y_pred) # On regarde précision du modèle de nos prédiction vers la réalité
La performance du modèle varie selon le split (random_state). On est beaucoup trop dépendant des éléments présents dans la phase d'apprentissage (train) et dans la validation (test).
On utilisant le principe de Cross Validation, on s'assure que chaque ligne à été en phase d'apprentissage (train) ainsi que dans la phase de validation (test) :
In [75]:
from sklearn.cross_validation import KFold
kf = KFold(25, n_folds=5, shuffle=False)
# print the contents of each training and testing set
print '{} {:^61} {}'.format('Iteration', 'Training set observations', 'Testing set observations')
for iteration, data in enumerate(kf, start=1):
print '{:^9} {} {:^25}'.format(iteration, data[0], data[1])
Chaque élément apparait uniquement une fois dans la phase de test
In [76]:
from sklearn.cross_validation import cross_val_score
knn = KNeighborsClassifier(n_neighbors=3)
scores = cross_val_score(knn, X, y, cv=10, scoring='accuracy')
print scores
On a donc 10 mesures de performances différentes.
In [78]:
print "La performance moyenne est de : %s et un std de %s" %(np.mean(scores), np.std(scores))
Dans la grande majorité des cas, un algoryhme possèdent plusieurs paramètres. Changer ces paramètres influent sur le résultat :
In [27]:
import matplotlib.pyplot as plt
from mlxtend.data import iris_data
from mlxtend.evaluate import plot_decision_regions
from sklearn.ensemble import RandomForestClassifier
In [28]:
# Get Data
X, y = iris_data()
X = X[:,[0, 2]]
In [33]:
# To plot graph
for criterion in ['gini', 'entropy']: # Criterion
for n_estimators in [3, 15]: # You can change this value if you want to play
RFC = RandomForestClassifier(criterion=criterion, n_estimators=n_estimators, random_state=12)
RFC.fit(X,y)
title = criterion + " + " + str(n_estimators)
fig = plot_decision_regions(X=X, y=y, clf=RFC, legend=2)
plt.title(title)
plt.show()
In [ ]: