Sandrine Henry
Data Science Portfolio
Data Science Portfolio
Le dataset sur lequel j'ai travaillé provient du UCI Machine Learning Repository.
Source : https://archive.ics.uci.edu/ml/datasets/census+income.
Les données du set proviennent du recensement de 1994 aux Etats-unis. L’objectif sera ici de prédire si le revenu d’un individu est de plus 50K$ ou pas (grâce à la variable « Income »).
Comme il n'y a que 2 résultats possible, la méthode de ML sera celle de classification : régression logistic, SVM, forest tree etc…
On pourra tester plusieurs de ces modèles pour déterminer le plus efficace.
# Importation des librairies:
import numpy as np
import pandas as pd
%matplotlib inline
import seaborn as sns
import matplotlib.pyplot as plt
La première étape est d’analyser les données et de les nettoyer
adult_data = pd.DataFrame(pd.read_csv('dataset/adult.data', header=None))
adult_data.columns=['age','workclass','fnlwgt','education','education-num','marital-status','occupation','relationship','race','sex','capital-gain','capital-loss','hours-per-week','native-country','income']
adult_data.head()
adult_data.shape
adult_data.info()
#select les ligne <50k puis occupation avec unique idem >50k puis
#adult_data[adult_data['income']==' <=50K'].occupation.unique()
#adult_data[adult_data['income']==' >50K'].occupation.unique()
La dataset contient 32561 lignes et 15 colonnes qui pour la suite pourraient se diviser ainsi :
Après recherche, la variable "fnlwgt" représente le poids final, qui correspond au « nombre d'unités de la population cible représentées par l'unité répondante ». </br>
La variable "education_num" correspond au nombre total d'années d'études, elle est la représentation numérique de la variable éducation. Je peux tout de même faire un table de corrélation pour confirmer cette info.</br>
La variable "relationship" représente de la personne interrogée au sein de la famille. </br> "capital_gain" et "capital_loss" sont des revenus autres que le salaire.</br>
Pour la suite du travail, on pourra supprimer la variable « education » puisque nous avons sa représentation numérique. Ce qui nous évitera pour cette variable de passer par l’étape get_dummies.
Pour supprimer d'éventuelles colonnes qui auraient un effet sur le modèle.
adult_data_num = adult_data.select_dtypes(include=['int64'])
adult_data_num_corr = adult_data_num.corr()
# Set up the matplotlib figure
fig, ax = plt.subplots(figsize=(9, 7))
# Generate a custom diverging colormap #
cmap="YlGnBu"
# Draw the heatmap with the mask and correct aspect ratio (mask=mask)
ax = sns.heatmap(adult_data_num_corr, cmap=cmap, annot=True, annot_kws={"size": 10},square=True, linewidths=.5)
Les variables les plus corrélées sont celles qui dans le graph ont un grand nombre de cases à la couleur très sombre. Ici, les variables numériques ne sont pas corrélées entre elles.
print('Nb de pays:',adult_data['native-country'].value_counts().count()) ,adult_data['native-country'].value_counts()
adult_data['native-country'].value_counts()/len(adult_data)*100
Pour ce qui est de la variable « Country », on compte 42 entrées : 40 pays, 1 'South'et 1 de type NC (« ? »).
On peut pour cette colonne par exemple créer une nouvelle variable qui regrouperait les pays par continent dès lors que ce n’est pas les USA qui représentent 89,5% des répondants.
Pour les lignes NC, je vais les supprimer. Ca fera 583 lignes en moins sur 32561. On travaillera donc avec 31898 lignes.
adult_data['native-country'].unique()
America=[' Cuba', ' Jamaica', ' Mexico',' Puerto-Rico', ' Honduras',' Canada',' Columbia',' Ecuador',' Haiti', ' Dominican-Republic',' Guatemala', ' Peru', ' Outlying-US(Guam-USVI-etc)', ' Trinadad&Tobago', ' Nicaragua',' El-Salvador']
Asia = [' India',' Iran', ' Philippines',' Cambodia', ' Thailand',' Laos',' Taiwan', ' China', ' Japan',' Vietnam', ' Hong']
Europe =[' England', ' Germany',' Italy', ' Poland',' Portugal',' France', ' Yugoslavia',' Scotland', ' Greece', ' Ireland', ' Hungary', ' Holand-Netherlands']
adult_data = adult_data.assign(group_country=adult_data['native-country'].map(lambda x: 'America' if x in America else ('Asia' if x in Asia else ('Europe' if x in Europe else x))))
adult_data['group_country'].value_counts()
Je vais peux ensuite supprimer la colonne 'native-country' et les lignes contenant "?" et "South" dont on ne sait pas à quoi cela se réfère.
adult_data.drop(adult_data[adult_data['group_country'] ==' ?'].index, inplace = True )
adult_data.drop(adult_data[adult_data['group_country'] ==' South'].index, inplace = True )
adult_data['group_country'].value_counts()
adult_data.drop(columns = 'native-country',inplace = True)
adult_data.head()
adult_data.shape
Je regarde la distribution de la Target.
print(adult_data.groupby('income').size())
Je passe cette colonne en ordinal pour plus faciliter les calculs.
adult_data['income_ordinal'] = adult_data['income'].map(lambda x: 1 if x==' >50K' else 0)
adult_data['income_ordinal'].value_counts()
sns.countplot(x='income',data=adult_data)
plt.title('Distribution Income')
plt.xlabel('Income')
plt.ylabel('Nb of persons')
adult_data.head()
Pour les autres variables, je n'ai rien vu de particulier. Mis à part qu'il faudra vérifier s'il n'y a pas de valeurs manquantes.
adult_data.isna().sum().sum()
Il n'y a pas de valeurs manquantes. Je peux passer à la partie ML
Je sépare les variables en Features et Target
# y pour la Target
y= adult_data["income_ordinal"]
# X pour les Features
X=adult_data.drop(columns=['income_ordinal','income'])
Je peux maintenant créer des variables ordinales depuis les variables catégorielles pour les Features.
X = pd.get_dummies(X)
X.head()
Je réalise un split classique de type 80% pour le training et 20% pour le test.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y ,train_size=0.80, test_size=0.20)
X_train.shape, X_test.shape, y_train.shape, y_test.shape
Je décide de passer par la méthode de cross-validation pour choisir mon modèle de prédiction.
La validation croisée en français est une méthode qui permet d'estimer les performances de généralisation de plusieurs modèles à partir de l’ensemble d’apprentissage. Cette estimation pourra être comparée à l’estimation obtenue sur l’ensemble de test mis de côté au départ.
La cross validation consiste à recommencer sur plusieurs découpages train/test différents du jeu de données initial de manière à s’assurer que la prédiction est stable et éviter d'overfitting.
from sklearn.model_selection import cross_val_score
from sklearn import metrics
print('Liste des scores existants dans le module sklearn:\n\n',metrics.SCORERS.keys())
Le score de comparaison que je choisis est l'Accuracy
: nb de bonnes predictions (TP) sur l'ensemble des prédictions.
Je vais tester les modèles suivant :LogisticRegression
, DecisionTreeClassifier
, KNeighborsClassifier
et RandomForestClassifier
.
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.ensemble import RandomForestClassifier
print("Rf:")
accuracy = cross_val_score(RandomForestClassifier(n_estimators=100, max_depth=2,random_state=0), X_train, y_train, scoring='accuracy', cv = 10)
print(accuracy)
print("Accuracy of Random Forest is: " , accuracy.mean()*100)
print("\n\nLog:")
#print(cross_val_score(log_class, X_train, y_train, scoring='accuracy', cv = 10))
accuracy = cross_val_score(LogisticRegression(solver='liblinear'), X_train, y_train, scoring='accuracy', cv = 10)
print(accuracy)
print("Accuracy of LogisticRegression is: " , accuracy.mean()*100)
print("\n\nK Neighbors:")
#print(cross_val_score(knn_class, X_train, y_train, scoring='accuracy', cv = 10))
accuracy = cross_val_score(KNeighborsClassifier(n_neighbors=3), X_train, y_train, scoring='accuracy', cv = 10)
print(accuracy)
print("Accuracy of K Neighbors is: " , accuracy.mean()*100)
print("\n\nDecision Tree:")
#print(cross_val_score(dtc_class, X_train, y_train, scoring='accuracy', cv = 10))
accuracy = cross_val_score(DecisionTreeClassifier(),X_train, y_train, scoring='accuracy', cv = 10)
print(accuracy)
print("Accuracy of Decision Tree is: " , accuracy.mean()*100)
Au regard des scores le modèle le plus probant est celui du Decision Tree
. Je peux aussi travailler sur le Logistic Regression
1) established the parameters to gris-search. it is important to note that these parameters change depending on what type of model we are building. Be sure to look up the model specific documentation for parameter explanation.
2) Running the grid search. this step may take a long time to run depending on the data and number of parameters.
3) Setting up the grid-serach. note how the parameter are wrapped within a dictionary
4) fitting the grid to the data
5) Depending on the designed parameter for measuring the model, will print the best score throughout the Grid Search
6) Print the best parameters used for the highest score of the model
<a>https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.GridSearchCV.html#sklearn.model_selection.GridSearchCV</a>
<a>https://medium.com/@elutins/grid-searching-in-machine-learning-quick-explanation-and-python-implementation-550552200596</a>
from sklearn.model_selection import GridSearchCV
model = DecisionTreeClassifier()
criterion=['gini','entropy']
max_depth=[5,10,50,None]
splitter=['best','random']
grid = GridSearchCV(estimator=model, cv=5, param_grid=dict(criterion=criterion,max_depth=max_depth,splitter=splitter))
criterion : string, optional (default=”gini”)
The function to measure the quality of a split. Supported criteria are “gini” for the Gini impurity and “entropy” for the information gain.
splitter : string, optional (default=”best”)
The strategy used to choose the split at each node. Supported strategies are “best” to choose the best split and “random” to choose the best random split.
max_depth : int or None, optional (default=None)
The maximum depth of the tree. If None, then nodes are expanded until all leaves are pure or until all leaves contain less than min_samples_split samples.
grid.fit(X_train,y_train)
print(grid.best_score_)
print(grid.best_params_)
from sklearn.model_selection import GridSearchCV
grid={"C":np.logspace(-3,3,7), "penalty":["l1","l2"]}
logreg=LogisticRegression()
logreg_cv=GridSearchCV(logreg,grid,cv=5)
logreg_cv.fit(X_train,y_train)
print(logreg_cv.best_score_)
print(logreg_cv.best_params_)
print("\n\nLog:")
#print(cross_val_score(log_class, X_train, y_train, scoring='accuracy', cv = 10))
accuracy = cross_val_score(LogisticRegression(C=1.0, penalty ='l1', solver='liblinear'),
X_train, y_train, scoring='accuracy', cv = 10)
print(accuracy)
print("Accuracy of LogisticRegression is: " , accuracy.mean()*100)
print("\n\nDecision Tree:")
#print(cross_val_score(dtc_class, X_train, y_train, scoring='accuracy', cv = 10))
accuracy = cross_val_score(DecisionTreeClassifier(criterion='entropy', max_depth=10, splitter='best'),
X_train, y_train, scoring='accuracy', cv = 10)
print(accuracy)
print("Accuracy of Decision Tree is: " , accuracy.mean()*100)
Note : En tenant compte du nombre de lignes. faire un value counts sur le données originel pour voir la répartition des classes (positve:négatif) cela permet de déduire la paramètre de CV pour bien faire apprendre le modele
dtc_class = DecisionTreeClassifier(criterion='entropy', max_depth=10, splitter='best')
# fitting the model
dtc_class.fit(X_train, y_train)
# predict the response
y_test_predict_dtc = dtc_class.predict(X_test)
from sklearn.metrics import confusion_matrix
# Confusion_matrix
confusion_matrix_dtc = confusion_matrix(y_test, y_test_predict_dtc)
print('\nconfusion_matrix:\n', confusion_matrix_dtc)
def plot_confusion_matrix(cm, title='Confusion matrix', cmap=plt.cm.Oranges):
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title)
plt.colorbar()
ax = plt.gca()
ax.set_xticklabels((ax.get_xticks() +1).astype(str))
plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label')
cm = confusion_matrix_dtc
np.set_printoptions(precision=1) #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
print('Confusion matrix')
print(cm)
fig, ax = plt.subplots()
plot_confusion_matrix(cm)
plt.show()
print('\nFeature_importances:\n', dict(zip(X.columns,dtc_class.fit(X_train, y_train).feature_importances_)))
pd.Series(dtc_class.feature_importances_, index=X_train.columns).nlargest(4).plot(kind='bar',color='#86bf91')