Skip to content

Instantly share code, notes, and snippets.

@ohe
Created January 31, 2018 11:47
Show Gist options
  • Select an option

  • Save ohe/bfd925a867d2f32c5456786ee8680747 to your computer and use it in GitHub Desktop.

Select an option

Save ohe/bfd925a867d2f32c5456786ee8680747 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"text-align: center\"><FONT color=\"#0B614B\" face=\"Lucida Sans Unicode\">Jaime Costa Centena - Janvier 2018 </h3>\n",
"\n",
"<h3 style=\"text-align: center\"> </h3>\n",
" <center> <FONT size=\"5\"color=\"#e888\" style=\"b\" face=\"Lucida Sans\n",
" Unicode\">---------------------------------------------------------------------</FONT> </h1>\n",
" <center> <FONT size=\"5\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\">Exercice</FONT> </h1>\n",
" <center> <FONT size=\"5\"color=\"#e888\" style=\"b\" face=\"Lucida Sans Unicode\">---------------------------------------------------------------------</FONT> </h1>"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"<FONT size=\"5\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\">Énoncé et commentaires</p><p>\n",
"</FONT> </h1>\n",
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>Le problème était de déceler au sein d'une base de données constituée de prénoms et noms les utilisateurs qui auraient interverti ces derniers.\n",
"</p><p>\n",
"\n",
"J'ai divisé le traitement du problème en quatre parties: \n",
"\n",
"<p>\n",
"(1) cŕeation d'une base de données la plus réaliste possible\n",
"</p><p>\n",
"(2) choix des features\n",
"</p><p>\n",
"(3) choix des algorithmes et entraînement\n",
"</p><p>\n",
"(4) performance\n",
"</p><p>\n",
"\n",
"Les questions subsidiaires sont traitées à la fin de ce notebook </FONT> \n",
"\n",
"</h1>\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"text-align: center\"> </h3>\n",
" <center> <FONT size=\"5\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\">Création de la base</FONT> </h1>\n",
" <center> <FONT size=\"5\"color=\"#e888\" style=\"b\" face=\"Lucida Sans Unicode\">---------------------------------------------------------------------</FONT> </h1>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>L'énoncé ne comprennant pas de database extensive, j'ai préféré en créer une pour avoir assez de données sur lesquelles traiter le problème (l'énoncé présuppose par ailleurs un nombre de clients de plusieurs milliers, donc qu'une telle base existe). \n",
"</p><p>\n",
"Le premier problème est qu'il ne suffit pas de créer des vecteurs \"prénom+nom\" en prenant les deux élements de façon aéatoire dans un dataset, puisqu'il faut que leur répartition soit réaliste (la distribution des prénoms et noms dans la population n'est pas équiprobable - on trouvera plus de \"Thomas\" que de \"Romuald\" en France par exemple).\n",
"\n",
"<p>\n",
"J'ai donc trouvé une base des noms et prénoms donnés aux États-Unis, qui comprend aussi leur fréquence. Elle est disponible ici : <a href=\"https://www.census.gov/topics/population/genealogy/data/1990_census/1990_census_namefiles.html\">données du recensement de 1990 aux Etats-Unis</a>.\n",
"\n",
"Cette base comprendra aussi un certain nombre d'erreurs, dont la proportion est à choisir. J'ai fait l'hypothèse que cette base était le seul outil de travail.\n",
"</p><p>\n",
"J'ai aussi fait le choix de travailler avec un trainset très réduit, pour montrer que malgré cela les algorithmes présentés peuvent avoir de bons résultats."
]
},
{
"cell_type": "code",
"execution_count": 81,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 82,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"num=2000 #Nombre de personnes ayant inscrit correctement leur nom et prénom\n",
"err=150 #Nombre de personnes ayant interverti leur nom et prénom\n",
"\n",
"\n",
"last = pd.read_csv('last_names.csv',header=None)\n",
"last.columns = ['name', 'freq']\n",
"first_m= pd.read_csv('first_m.csv',header=None)\n",
"first_f= pd.read_csv('first_f.csv',header=None)\n",
"\n",
"first=pd.concat([first_m,first_f])\n",
"\n",
"#on cree les noms \"justes\"\n",
"rand_first=first.iloc[:,0].sample(n=num,weights=first.iloc[:,1],replace=True)\n",
"rand_last=last.iloc[:,0].sample(n=num,weights=last.iloc[:,1],replace=True)\n",
"db_juste=pd.concat([rand_first.reset_index().iloc[:,1],rand_last.reset_index().iloc[:,1]], axis=1)\n",
"db_juste.columns = ['first', 'last']\n",
"#on cree les noms \"erronnés\"\n",
"rand_first=first.iloc[:,0].sample(n=err,weights=first.iloc[:,1],replace=True)\n",
"rand_last=last.iloc[:,0].sample(n=err,weights=last.iloc[:,1],replace=True)\n",
"db_err=pd.concat([rand_last.reset_index().iloc[:,1],rand_first.reset_index().iloc[:,1]], axis=1)\n",
"db_err.columns = ['first', 'last']\n",
"\n",
"#données finales\n",
"db=pd.concat([db_err.reset_index(),db_juste.reset_index()])\n",
"\n",
"#on mélange le tout\n",
"db_final=db.sample(frac=1).iloc[:,1:3].reset_index().iloc[:,1:3]\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"text-align: center\"> </h3>\n",
" <center> <FONT size=\"5\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\">Features</FONT> </h1>\n",
" <center> <FONT size=\"5\"color=\"#e888\" style=\"b\" face=\"Lucida Sans Unicode\">---------------------------------------------------------------------</FONT> </h1>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>\n",
"Quelles features à retenir ? (i.e. sur quels éléments notre algorithme se basera pour s'entrainer et prédire ?)</p><p>\n",
"\n",
"S'il était possible de faire des choix plus \"sémantiques\" ou \"lingüistiques\" (par exemple sur les ṕremières et dernières lettres des prénoms et noms), j'ai préférer m'éloigner de ce terrain dont l'efficacité pourrait être très variable selon les langues (pour prendre un exemple, un tel algorithme en Arménie serait très efficace puisque la quasi-totalité noms de familles contiennent le même suffixe -ian).\n",
"</p><p>\n",
"Il est par contre raisonnable de penser que, par construction, la distribution des prénoms diffère, certes à des degrés divers, de celles des noms dans la quasi-totalité des cultures. Cette différence de distribution devrait se retrouver dans un échantillon suffisamment large.\n",
"</p><p>\n",
"Nous allons donc construire une fonction qui extrait quatre features d'un vecteur \"prénom + nom\" donné:\n",
"</p><p>\n",
"(1) le nombre d'occurence du prénom parmi les autres prénoms de la base\n",
"</p><p>\n",
"(2) le nombre d'occurence du prénom parmi les autres noms de famille de la base\n",
"</p><p>\n",
"(3) le nombre d'occurence du noms de famille parmi les autres prénoms de la base\n",
"</p><p>\n",
"(4) le nombre d'occurence du noms de famille parmi les autres noms de famille de la base\n",
"</p><p>\n",
"\n",
"Afin d'agiliser les calculs pour plus tard, j'ai aussi crée une fonction qui donne le résultat obtenu si nom et prénom étaient intervertis (afin de ne plus avoir à en intervertir manuellement).\n",
"</p><p>\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 83,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def features(vect):\n",
" ff=db_final[\"first\"].str.count(vect[0]).sum(axis=0)\n",
" fl=db_final[\"last\"].str.count(vect[0]).sum(axis=0)\n",
" lf=db_final[\"first\"].str.count(vect[1]).sum(axis=0)\n",
" ll=db_final[\"last\"].str.count(vect[1]).sum(axis=0)\n",
" return([ff,fl,lf,ll])"
]
},
{
"cell_type": "code",
"execution_count": 84,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def features_faux(vect):\n",
" lf=db_final[\"first\"].str.count(vect[0]).sum(axis=0)\n",
" ll=db_final[\"last\"].str.count(vect[0]).sum(axis=0)\n",
" ff=db_final[\"first\"].str.count(vect[1]).sum(axis=0)\n",
" fl=db_final[\"last\"].str.count(vect[1]).sum(axis=0)\n",
" return([ff,fl,lf,ll])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>\n",
"Nous voyons ci-dessous qu'il est équivalent d'extraire les features avec \"features_faux\" que d'intervertir nom et prénom."
]
},
{
"cell_type": "code",
"execution_count": 85,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[8, 1, 0, 0]\n",
"[0, 0, 8, 1]\n",
"[0, 0, 8, 1]\n"
]
}
],
"source": [
"print(features([\"DONALD\",\"TRUMP\"]))\n",
"print(features_faux([\"DONALD\",\"TRUMP\"]))\n",
"print(features([\"TRUMP\",\"DONALD\"]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>\n",
"Nous transformons notre base initiale en train set. </p><p>\n",
"Quelques remarques importantes sur les hypothèses qui nous permettront d'utiliser ce train set:\n",
"</p><p>\n",
"Notre train set n'est pas parfait (il contient les erreurs que nous y avons mis exprès lors de la construction de la base. C'est la situation dans laquelle nous nous trouverions si ce cas était réelle, et que traiter les données manuellement pour les rendre toutes justes était trop couteux. Il est possible de travailler avec une telle base à condition que le nombre d'erreurs ne soit pas trop élevé, qui est l'hypothèse que nous faisons.\n",
"</p><p>\n",
"Pour avoir un train set composé d'éléments justes et faux nous séparons la base en deux, et intervertissons l'ordre de \"prénom nom\" pour la deuxième partie. Nous avons donc une partie de la base très majoritairement juste, et une autre très majoritairement fausse.\n"
]
},
{
"cell_type": "code",
"execution_count": 87,
"metadata": {},
"outputs": [],
"source": [
"#creation du train set\n",
"justes=db_final.values[1000:,:]\n",
"justes2=np.apply_along_axis(features,1,justes)\n",
"faux=db_final.values[:1000,:]\n",
"faux2=np.apply_along_axis(features_faux,1,faux)\n",
"train=np.concatenate((justes2,faux2),axis=0)\n",
"\n",
"#creation du vecteur target\n",
"target=np.concatenate((np.zeros(len(justes2)),np.ones(len(faux2))))"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"<h3 style=\"text-align: center\"> </h3>\n",
"<center> <FONT size=\"5\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\">Algorithmes</FONT> </h1>\n",
"\n",
"<center> <FONT size=\"5\"color=\"#e888\" style=\"b\" face=\"Lucida Sans Unicode\">---------------------------------------------------------------------</FONT> </h1>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>\n",
"Le choix de nos algorithmes dépend en grande partie de notre \"fonction d'utilité\".\n",
"</p><p>\n",
"<u>Hypothèse 1 :</u> \n",
"Nous pouvons considérer que nous voulons autant de clients satisfaits que possible, et donc que nous sommes indifférents entre d'avoir un faux positif supplémentaire (un client qui a bien écrit son nom que l'on détecte comme une erreur) si nous détectons une \"vraie erreur\" supplémentaire.\n",
"</p><p>\n",
"<u>Hypothèse 2 :</u> \n",
"Mais nous pouvons aussi penser qu'il faut réduire au maximum le taux de faux positif, quitte à ne pas détecter des erreurs.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>\n",
"\n",
"Sous l'hypothèse 1, j'ai fait le choix d'une méthode d'ensemble, combinant un séparateur linéaire, une méthode des k plus proches voisins (k-NN) et une classification naïve bayésienne. Le classificateur d'ensemble emploie un mode de vote \"soft\", qui tient compte des probabilités que chaque modèle assigne respectiviement à l'existence d'une erreur."
]
},
{
"cell_type": "code",
"execution_count": 88,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"VotingClassifier(estimators=[('GNB', GaussianNB(priors=None)), ('lsvc', SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,\n",
" decision_function_shape='ovr', degree=3, gamma='auto', kernel='linear',\n",
" max_iter=-1, probability=True, random_state=None, shrinking=True,\n",
" tol=0.001, verbose=False)), ('knn', KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',\n",
" metric_params=None, n_jobs=1, n_neighbors=5, p=2,\n",
" weights='uniform'))],\n",
" flatten_transform=None, n_jobs=1, voting='soft', weights=None)"
]
},
"execution_count": 88,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.ensemble import VotingClassifier\n",
"from sklearn.naive_bayes import GaussianNB\n",
"from sklearn import svm\n",
"from sklearn.neighbors import KNeighborsClassifier\n",
"\n",
"clf1 = GaussianNB()\n",
"clf2= svm.SVC(kernel='linear',probability=True)\n",
"knn = KNeighborsClassifier()\n",
"\n",
"\n",
"eclf1 = VotingClassifier(estimators=[('GNB', clf1), ('lsvc', clf2), ('knn', knn)], voting='soft')\n",
"\n",
"eclf1.fit(train, target)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>\n",
"\n",
"Sous l'hypothèse 2, afin de réduire au maximum les chances de faux positifs, je n'ai retenu que les points qui étaient considérés faux par les trois algorithmes simultanément."
]
},
{
"cell_type": "code",
"execution_count": 89,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',\n",
" metric_params=None, n_jobs=1, n_neighbors=5, p=2,\n",
" weights='uniform')"
]
},
"execution_count": 89,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.naive_bayes import GaussianNB\n",
"gnb = GaussianNB()\n",
"gnb.fit(train, target)\n",
"\n",
"from sklearn import svm\n",
"linear_svc= svm.SVC(kernel='linear')\n",
"linear_svc.fit(train, target)\n",
"\n",
"from sklearn.neighbors import KNeighborsClassifier\n",
"knn = KNeighborsClassifier()\n",
"knn.fit(train, target)"
]
},
{
"cell_type": "code",
"execution_count": 90,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def pred_hyp2(test):\n",
" y_log=Logistic1.predict(test)\n",
" y_gnb=gnb.predict(test)\n",
" y_knn=knn.predict(test)\n",
" y_lsvc=linear_svc.predict(test)\n",
" return(y_log*y_gnb*y_knn*y_lsvc)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"text-align: center\"> </h3>\n",
"<center> <FONT size=\"5\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\">Performance</FONT> </h1>\n",
"\n",
"<center> <FONT size=\"5\"color=\"#e888\" style=\"b\" face=\"Lucida Sans Unicode\">---------------------------------------------------------------------</FONT> </h1>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>\n",
"Remarques préliminaires à la mesure de la performance:\n",
"</p><p>\n",
"-Comme il a été dit précédemment, tout dépend de nos critères de mesure de la performance (poids des erreur de première et seconde espèce).\n",
"</p><p>\n",
"-Il est important de souligner que le taux de clients se trompant est d'une très grande importance. Ainsi, si ce taux est minime un très bon algorithme sera inutile puisqu'il induira nécessairement plus de \"faux positifs\" que d'erreurs qu'il pourra trouver (ceci est très bien illustré par le cas extrême où on fait tourner l'algorithme dans une base où il n'y a aucune erreur).\n",
"</p><p>\n",
"-La manière de procéder ci-dessous est discutable. Dans l'optique d'une mise en situation réelle il aurait été nécessaire de faire tourner l'algorithme sur le tout premier set (puisqu'en théorie nous n'en avons qu'un seul), ce qui pose un certain nombre de questions (même test et train set, etc...). </p><p>\n",
"Dans un souci de clarté et de conscision j'ai préféré le faire sur un deuxième set ainsi que d'éviter de m'étendre sur d'autres formes de mesurer la performance (vu que l'énoncé appellait à une mise en pratique immédiate). Néanmoins s'ils étaient nécessaires les outils sont très rapidement implémentables via sklearn.metrics.\n",
"</p><p>\n",
"</p><p>\n",
"</p><p>\n",
"Nous allons donc créer un deuxième test set, où la quantité de données fausse sera exagérée, afin de pouvoir tester nos deux algorithmes et pouvoir interpréter les résultats.\n",
"</p><p>\n",
"Nous nous intéresserons ensuite au cas où le nombre d'erreurs est plus faible et plus proche de celui supposé initalement.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 126,
"metadata": {},
"outputs": [],
"source": [
"num=2000 #nb de personnes dans la database\n",
"err=1000 #nombre d'erreurs PARMI les élements de la database\n",
"\n",
"last = pd.read_csv('last_names.csv',header=None)\n",
"last.columns = ['name', 'freq']\n",
"first_m= pd.read_csv('first_m.csv',header=None)\n",
"first_f= pd.read_csv('first_f.csv',header=None)\n",
"\n",
"first=pd.concat([first_m,first_f])\n",
"\n",
"#on cree les noms \"justes\"\n",
"rand_first=first.iloc[:,0].sample(n=num,weights=first.iloc[:,1],replace=True)\n",
"rand_last=last.iloc[:,0].sample(n=num,weights=last.iloc[:,1],replace=True)\n",
"db=pd.concat([rand_first.reset_index().iloc[:,1],rand_last.reset_index().iloc[:,1]], axis=1)\n",
"db.columns = ['first', 'last']\n",
"\n",
"faux=db.values[:err,:]\n",
"faux2=np.apply_along_axis(features_faux,1,faux)\n",
"\n",
"justes=db.values[err:,:]\n",
"justes2=np.apply_along_axis(features,1,justes)\n",
"\n",
"test=np.concatenate((faux2,justes2),axis=0)"
]
},
{
"cell_type": "code",
"execution_count": 120,
"metadata": {},
"outputs": [],
"source": [
"def resultats(y_pred):\n",
" errors=np.flatnonzero(y_pred)\n",
" false_pos=np.where( errors > err )\n",
" print(\"L'algorithme trouve %s erreurs\" % len(errors))\n",
" print(\"Parmi lesquelles %s sont des faux positifs\" % len(false_pos[0]))\n",
" print(\"Et %s des vraies erreurs\" % (len(errors)-len(false_pos[0])))\n",
" print(\"Nous n'avons pas détecté %s erreurs\" % (err-((len(errors)-len(false_pos[0])))))\n",
" return()"
]
},
{
"cell_type": "code",
"execution_count": 121,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Pour la méthode d'ensemble, nous avons :\n",
"L'algorithme trouve 1081 erreurs\n",
"Parmi lesquelles 158 sont des faux positifs\n",
"Et 923 des vraies erreurs\n",
"Nous n'avons pas détecté 77 erreurs\n",
"\n",
"Pour la méthode 2, nous avons :\n",
"L'algorithme trouve 993 erreurs\n",
"Parmi lesquelles 125 sont des faux positifs\n",
"Et 868 des vraies erreurs\n",
"Nous n'avons pas détecté 132 erreurs\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 121,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"print(\"Pour la méthode d'ensemble, nous avons :\")\n",
"resultats(eclf1.predict(test))\n",
"print(\"\")\n",
"print(\"Pour la méthode 2, nous avons :\")\n",
"resultats(pred_hyp2(test))"
]
},
{
"cell_type": "code",
"execution_count": 124,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"num=2000 #nb de personnes dans la database\n",
"err=400 #nombre d'erreurs PARMI les élements de la database\n",
"\n",
"last = pd.read_csv('last_names.csv',header=None)\n",
"last.columns = ['name', 'freq']\n",
"first_m= pd.read_csv('first_m.csv',header=None)\n",
"first_f= pd.read_csv('first_f.csv',header=None)\n",
"\n",
"first=pd.concat([first_m,first_f])\n",
"\n",
"#on cree les noms \"justes\"\n",
"rand_first=first.iloc[:,0].sample(n=num,weights=first.iloc[:,1],replace=True)\n",
"rand_last=last.iloc[:,0].sample(n=num,weights=last.iloc[:,1],replace=True)\n",
"db=pd.concat([rand_first.reset_index().iloc[:,1],rand_last.reset_index().iloc[:,1]], axis=1)\n",
"db.columns = ['first', 'last']\n",
"\n",
"faux=db.values[:err,:]\n",
"faux2=np.apply_along_axis(features_faux,1,faux)\n",
"\n",
"justes=db.values[err:,:]\n",
"justes2=np.apply_along_axis(features,1,justes)\n",
"\n",
"test=np.concatenate((faux2,justes2),axis=0)"
]
},
{
"cell_type": "code",
"execution_count": 125,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Pour la méthode d'ensemble, nous avons :\n",
"L'algorithme trouve 636 erreurs\n",
"Parmi lesquelles 261 sont des faux positifs\n",
"Et 375 des vraies erreurs\n",
"Nous n'avons pas détecté 25 erreurs\n",
"\n",
"Pour la méthode 2, nous avons :\n",
"L'algorithme trouve 578 erreurs\n",
"Parmi lesquelles 221 sont des faux positifs\n",
"Et 357 des vraies erreurs\n",
"Nous n'avons pas détecté 43 erreurs\n"
]
},
{
"data": {
"text/plain": [
"()"
]
},
"execution_count": 125,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"print(\"Pour la méthode d'ensemble, nous avons :\")\n",
"resultats(eclf1.predict(test))\n",
"print(\"\")\n",
"print(\"Pour la méthode 2, nous avons :\")\n",
"resultats(pred_hyp2(test))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<h3 style=\"text-align: center\"> </h3>\n",
" <center> <FONT size=\"5\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\">Conclusion</FONT> </h1>\n",
" <center> <FONT size=\"5\"color=\"#e888\" style=\"b\" face=\"Lucida Sans Unicode\">---------------------------------------------------------------------</FONT> </h1>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>\n",
"Nous voyons bien que l'intérêt de l'algorithme dépend beaucoup du taux d'erreur des utilisateurs. </p><p>\n",
"\n",
"Il peut néanmoins être utile avant une vérification humaine, facilitée par la rédiction du nombre de données à traiter.</p><p>\n",
"Il y aurait de nombreuses pistes d'amélioration, par exemple via une transformation des features par une fonction, ou une meilleur connaissance de l'environnement d'où sont issus les utilisateurs (ce qui pourrait permettre l'utilisation de critères plus lingüistiques comme les dernières lettres du nom de famille. .</p><p>Évidemment, une base d'entrainement plus grande améliorerait la performance (l'énoncé ne précisant pas le nombre d'utilisateurs, j'ai préférer entrainer les algorithmes avec peu de données, pour voir leur réaction même lorsque le trainset est réduit)."
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"<h3 style=\"text-align: center\"> </h3>\n",
" <center> <FONT size=\"5\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\">Questions subsidiaires</FONT> </h1>\n",
" <center> <FONT size=\"5\"color=\"#e888\" style=\"b\" face=\"Lucida Sans Unicode\">---------------------------------------------------------------------</FONT> </h1>"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>\n",
"Comment puis-je \"stocker\" l'information apprise pour la ré-appliquer à d'autres bases de données ?"
]
},
{
"cell_type": "code",
"execution_count": 128,
"metadata": {},
"outputs": [],
"source": [
"#via \"pickle\":\n",
"import pickle\n",
"pickle.dump(eclf1, open(\"eclf1\", 'wb'))\n",
"#pour réouvrir le modèle :\n",
"loaded_model = pickle.load(open(\"eclf1\", 'rb'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>\n",
"Que peut-on dire de l'entropie d'un nom comparée à celle d'un prénom ?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<FONT size=\"3\"color=\"#0B614B\" style=\"b\" face=\"Lucida Sans Unicode\"><p>\n",
"\n",
"Il raisonnable de penser qu'il est plus commun de partager un prénom qu'un nom de famille. Dès lors, et étant donné que sa probabilité d'occurence est inférieure à 0.5, l'entropie d'une prénom devrait être supérieure à celle d'un nom (cf https://www.researchgate.net/figure/The-relation-between-the-entropy-of-a-word-and-its-probability-of-occurrence_267803123 )."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment