L’apprentissage automatique et l’apprentissage profond sont des branches de l’intelligence artificielle (IA) utilisées pour faire des prédictions sur des nouveaux jeux de données qui n’ont pas été utilisés pour entraîner l’algorithme. Ces méthodes sont basées sur des notions statistiques qui peuvent différées selon qu’il s’agisse d’un problème de régression ou de classification. Une bonne prédiction requière une certaine méthodologie allant du nettoyage de données au choix d’algorithme en passant par l’extraction de variables pertinentes pour le modèle. Dans cet article, il sera question d’expliquer la bonne méthodologie à adopter pour faire une bonne prédiction avec du machine learning. Cette méthodologie sera beaucoup axée sur le feature engineering ou l’extraction des variables pertinente pour votre modèle au vu de l’ensemble des variables que constitue votre base de données ( variables initiales et variaibles obtenues après enrichissement de votre base de données)
Définir le modèle
In [1]: import seaborn as sns import pandas as pd data = sns.load_dataset('iris') data["species"]=pd.Categorical(data["species"]) data["species"]=data['species'].cat.codes In [2]: features= data.drop(["species"],axis=1) target=data.species
Quelques technique de features engineering
Comme technique de sélection de variable, nous pouvons en citées le coefficient de corrélation, Random Forest, PCA, Régression Logistique, GLM, RFE (Recursive Feature Extraction sans Crossvalidation) ou RFECV (Recursive Feature Extraction avec Cross-validation), Test d’indépendance (Khi-2). Ces techniques peuvent être combinatoires.
Coefficient de corrélation ou corrélogramme
In [3]: import matplotlib.pyplot as plt import seaborn as sns # changer scatter par reg pour ne pas faire une regression sns.pairplot(data, kind="scatter") plt.show()
PCA
Avec cette technique de réduction de dimension, vous pouvez synthétiser l’ensemble de vos informations en un certain nombre de dimensions qui résumerons l’ensemble de vos données. Au lieu d’utiliser l’ensemble des variables, il est parfois très intéressant d’utiliser un résumé des variables car elle permet d’éviter la corrélation entre variables indépendantes.
In [ ]: from sklearn.decomposition import PCA from sklearn.preprocessing import LabelEncoder pca = PCA(n_components=2) X_pca = pca.fit_transform(features) #X_Test_pca=pca.fit_transform(X_Test) #PCA_df = pd.DataFrame(data = X_pca, columns = ['PC1', 'PC2'])# ,'PC3', 'PC4']) #, # 'PC5', 'PC6']) #print(pca.explained_variance_) #PCA_df = pd.concat([PCA_df, data['features']], axis = 1) #PCA_df['features'] = LabelEncoder().fit_transform(PCA_df['features']) #Y_data=LabelEncoder().fit_transform(target) #PCA_df.head()
ICA ( Idependant Composant Analysis )
Independant Composant Analysis est une technique similaire au PCA qui aussi permet la réduction de dimension. Toutefois, il faut faire des itérations entre chacune de ses méthodes en testant avec les algorithmiques pour pouvoir choisir le meilleur parmi l’ensemble des méthodes.
In [347]: from sklearn.decomposition import FastICA # vous pouvez remplacer le 4 par le nombre de dimension que vous souhaitez avoir ica = FastICA(n_components=4) X_ica = ica.fit_transform(features)
LDA (Linear Discrimant Analysis)
Comme le PCA et l’ICA, le LDA permet également de faire une réduction de dimension
In [337]: from sklearn.discriminant_analysis import LinearDiscriminantAnalysis lda = LinearDiscriminantAnalysis(n_components=2) X_lda = lda.fit(features, target).transform(features) print('Original number of features:', X.shape[1]) print('Reduced number of features:', X_lda.shape[1]) Original number of features: 4 Reduced number of features: 2
LLE (Locally linear Embedding )
In [306]: from sklearn.manifold import LocallyLinearEmbedding embedding = LocallyLinearEmbedding(n_components=3) X_lle = embedding.fit_transform(features)
t-NSE (t-distributed Stochastic Neighbor Embedding)
In [11]: from sklearn.manifold import TSNE #start = time.process_time() tsne = TSNE(n_components=3, verbose=1, perplexity=40, n_iter=250) #X_tsne = tsne.fit_transform(features) #print(time.process_time() - start)
Auto Encoder & Decoder
In [364]: from keras.layers import Input, Dense from keras.models import Model input_layer = Input(shape=(X.shape[1] , )) encoded = Dense(3, activation='relu')( input_layer ) decoded = Dense(X.shape[1], activation='softmax')( encoded ) autoencoder = Model(input_layer, decoded) autoencoder.compile(optimizer='adam', loss='binary_crossentropy') #X1, X2, Y1, Y2 = train_test_split(features, features, test_size=0.3, # random_state=101) #autoencoder.fit(X1, Y1, # epochs=100, # batch_size=300, # shuffle=True, # verbose = 30 , # validation_data=(X2, Y2)) #encoder = Model(input_layer, encoded) #X_ae = encoder.predict(features)
Ces trois dernières techniques à savoir Locally linear Embedding, t-distributed Stochastic Neighbor Embedding, Auto Encoder & Decoder sont des techniques de Deep mais utilisable en machine learning pour faire du features ingineering
Recursive Feature Eliminate
Cette technique permet d’éliminer progressivement les features moins pertinents pour le modèle au fur et à mesure. Elle se base sur la notion du bagging. Elle a une particularité qui est la possibilité de le compiler avec l’algorithme qu’on souhaite utilisés pour notre modèle. Comme c’est le cas ici du Random Forest
In [ ]: from sklearn import ensemble from sklearn.metrics import confusion_matrix from sklearn.metrics import log_loss from sklearn.model_selection import cross_val_score params = {'bootstrap': True, 'max_depth': 50, 'max_features': 'sqrt', 'min_samples_leaf': 4, 'min_samples_split': 10, 'n_estimators': 800} rf_model= ensemble.RandomForestClassifier(**params) rf_model.fit(X_train, y_train) In [ ]: from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import StratifiedKFold from sklearn.feature_selection import RFECV rfecv = RFECV(estimator=rf_model, step=1, cv=StratifiedKFold(10), scoring='accuracy') In [ ]: rfecv.fit(features, target) In [ ]: print(' numbre features: {}'.format(rfecv.n_features_)) Liste des Features Importantes In [ ]: X.drop(X.columns[np.where(rfecv.support_ == False)[0]], axis=1, inplace=True) In [ ]: from sklearn import ensemble from sklearn.metrics import confusion_matrix from sklearn.metrics import log_loss from sklearn.model_selection import cross_val_score params = {'bootstrap': True, 'max_depth': 50, 'max_features': 'sqrt', 'min_samples_leaf': 4, 'min_samples_split': 10, 'n_estimators': 800} rf_model= ensemble.RandomForestClassifier(**params) rf_model.fit(X_train, y_train)
Random Forest
In [ ]: from sklearn.feature_selection import SelectFromModel feat_labels = X_train.columns feat=list() contrib=list() # Print the name and gini importance of each feature #for feature,contrib in zip(feat_labels, rf_model.feature_importances_): for feature in feat_labels: feat.append(feature) for contribut in rf_model.feature_importances_: contrib.append(contribut) #print(contrib) feat=pd.DataFrame(feat) contrib=pd.DataFrame(contrib) Table=pd.concat([feat,contrib],axis=1) Table.columns=["feature","contribution"] Table=Table.sort_values(by='contribution',ascending=False, na_position='first') Table In [ ]: from sklearn.feature_selection import SelectFromModel feat_labels = data.columns.drop(["list_features"]) # Print the name and gini importance of each feature for feature in zip(feat_labels, rf_model.feature_importances_): print( feature ) In [ ]: sfm = SelectFromModel(rf_model, threshold=0.05) # Train the selector sfm.fit(X_train, y_train) In [ ]: for feature_list_index in sfm.get_support(indices=True): print( feat_labels[feature_list_index ])
Logisitic method
Cette technique est facile à utiliser et rapide d’exécution. En effet, les variables dont la p-value est inférieur à 1% c’est-à-dire très significatif seront considérée comme influentes sur la variable dépendante.
In [ ]: import statsmodels.api as sm #data=data.drop(['mouvement'] ,axis =1) logit_model=sm.Logit(target,features) result=logit_model.fit() print(result.summary2())
Quelques techniques de normalisation
Cette étape peut parfois être très utile dans la mesure ou les données d’entrainement sont très différentes des données test.
Min max
In [ ]: from sklearn import preprocessing from sklearn.preprocessing import LabelEncoder min_max_scaler = preprocessing.MinMaxScaler() X_train_n =min_max_scaler.fit_transform(X_train) y_train_n =LabelEncoder().fit_transform(y_train.values.ravel()) X_test_n =min_max_scaler.fit_transform(X_test) y_test_n = LabelEncoder().fit_transform(y_test.values.ravel()) Mu Sigma In [1274]: from sklearn.preprocessing import StandardScaler from sklearn.preprocessing import LabelEncoder sc = StandardScaler() X_train_n = sc.fit_transform(X_train) X_test_n = sc.fit_transform(X_test) y_train_n=LabelEncoder().fit_transform(y_train.values.ravel()) y_test_n=LabelEncoder().fit_transform(y_test.values.ravel())
Hyper paramétrisation
Random Forest params
In [ ]: from sklearn.model_selection import RandomizedSearchCV # Weigth of each class in learning #class_weight= # Number of trees in random forest n_estimators = [int(x) for x in np.linspace(start = 200, stop = 2500, num = 10)] # Number of features to consider at every split max_features = ['auto', 'sqrt'] # Maximum number of levels in tree max_depth = [int(x) for x in np.linspace(10, 220, num = 11)] max_depth.append(None) # Minimum number of samples required to split a node min_samples_split = [2, 5, 10,15,20,40,100] # Minimum number of samples required at each leaf node min_samples_leaf = [1, 2, 4,66,8,50,100] # Method of selecting samples for training each tree bootstrap = [True, False] learning_rate = [int(x) for x in np.linspace(start = 0.1, stop = 1, num = 0.1)] # Create the random grid random_grid = {'n_estimators': n_estimators, 'max_features': max_features, 'max_depth': max_depth, 'min_samples_split': min_samples_split, 'min_samples_leaf': min_samples_leaf, 'bootstrap': bootstrap}
Hist Gradiant boosting params
In [94]: from sklearn.model_selection import RandomizedSearchCV # Number of trees in random forest max_iter = [int(x) for x in np.linspace(start = 200, stop = 2000, num = 10)] # Maximum number of levels in tree max_depth = [int(x) for x in np.linspace(10, 110, num = 11)] max_depth.append(None) min_samples_leaf = [1, 2,4,66,8,100,200,50,75] max_bins=[2,20,30,50,100,200,256] learning_rate=[0.1,0.5,0.9] loss=['auto','binary_crossentropy'] validation_fraction=[0.1,0.5,0.9] # Method of selecting samples for training each tree # Create the random grid random_grid = {'max_iter': max_iter, 'max_depth': max_depth, 'min_samples_leaf': min_samples_leaf, 'max_bins': max_bins, 'loss': loss, 'validation_fraction': validation_fraction }
Hyper paramétrisation GreadSearch
In [ ]: from sklearn.model_selection import GridSearchCV from sklearn import ensemble # Create the gridsearch grid_values = { 'bootstrap': [True,False] , 'max_depth': [20,30,40,50,60,70,80] , 'max_features': [1, 2] , 'min_samples_leaf': [3, 4, 5] , 'min_samples_split': [4,6,8, 10] , 'n_estimators': [100, 200, 1000] } rf_model = ensemble.RandomForestClassifier() grid_search = GridSearchCV(estimator = rf_model, param_grid = grid_values, cv = 5, n_jobs = -1, verbose = 2) grid_search.fit(X_train, y_train.values.ravel()) In [ ]: grid_search.best_params_ grid_search.best_score_
Hyperparamétrisation Random Search
In [211]: from sklearn.ensemble import HistGradientBoostingClassifier from sklearn import ensemble HistGbt_model= HistGradientBoostingClassifier() #rf_model= ensemble.RandomForestClassifier() rf_random = RandomizedSearchCV(estimator = rf_model, param_distributions = random_gri n_iter = 100, cv = 3, verbose=2, random_state=5, n_job # Fit the random search model #rf_random.fit(X_train, y_train.values.ravel()) In [ ]: rf_random.best_params_ rf_random.best_score_