rapport complété mais non corrigé
This commit is contained in:
parent
8c567aa307
commit
c0be900625
2 changed files with 71 additions and 15 deletions
53
rapport.md
53
rapport.md
|
@ -83,28 +83,69 @@ Dans cette section, nous allons créer des modèles pour les noms de famille pro
|
|||
|
||||
Pour chaque origine, nous allons normaliser les noms de famille en les mettant en minuscules et les convertissant en encodage ASCII. Nous allons ensuite construire des unigrammes pour chacun des noms de familles. Ceci nous permettra tout d'abord de disposer de listes de lettres au lieu de mots, ce qui facilitera la création des bigrammes et trigrammes. Celà nous permet aussi de mesurer la taille $V$ du vocabulaire, soit le nombre de caractères différents, incluant un caractère virtuel pour représenter la fin de mot.
|
||||
|
||||
### Création des k-grammes
|
||||
### Création des $k$-grammes
|
||||
|
||||
Pour convertir les mots en unigrammes, on utilise la fonction `list` qui retourne simplement une liste des caractères d'un mot. Puis, pour créer des k-grammes, on ajoute $k-1$ caractères de début de mot au début de la liste et $k-1$ caractères de fin de mot à la fin de cette liste. Ensuite, pour créer la liste des k-grammes, on en prend les éléments $k$ à la fois et on les joint ensemble dans une seule chaîne de caractères. Soit $U$ la liste des unigrammes, on sélectionne
|
||||
Pour convertir les mots en unigrammes, on utilise la fonction `list` qui retourne simplement une liste des caractères d'un mot. Puis, pour créer des $k$-grammes, on ajoute $k-1$ caractères de début de mot au début de la liste et $k-1$ caractères de fin de mot à la fin de cette liste. Ensuite, pour créer la liste des $k$-grammes, on en prend les éléments $k$ à la fois et on les joint ensemble dans une seule chaîne de caractères. Soit $U$ la liste des unigrammes, on sélectionne
|
||||
|
||||
$$U[i] \ldots U[i+k-1], \forall i \in [0,|U|-k]$$
|
||||
|
||||
### Création des modèles
|
||||
|
||||
On crée un modèle différent pour chacune des origines. Pour chaque nom présent dans la liste associée à une origine, on applique l'opération de normalisation, puis on extrait les unigrammes dans une liste. On accumule ceux-ci dans une liste de listes.
|
||||
Sur chacun des mots transformés en unigrammes, on développe les k-grammes pour $k \in [1,4]$. On effectue le compte de tous les k-grammes pour une origine, qu'on stocke dans un dictionnaire, puis on enregistre cette information (qui est notre modèle de langue) dans un dictionnaire de modèles dont la clé est de la forme (origine,$k$). Ceci nous permettra d'accéder aux modèles pour différentes valeurs de $k$ simultanément.
|
||||
Sur chacun des mots transformés en unigrammes, on développe les $k$-grammes pour $k \in [1,4]$. On effectue le compte de tous les $k$-grammes pour une origine, qu'on stocke dans un dictionnaire, puis on enregistre cette information (qui est notre modèle de langue) dans un dictionnaire de modèles dont la clé est de la forme (origine,$k$). Ceci nous permettra d'accéder aux modèles pour différentes valeurs de $k$ simultanément.
|
||||
|
||||
### Origine la plus probable
|
||||
|
||||
Le calcul de l'origine la plus probable d'un nom consiste à évaluer, pour chacune des origines, la probabilité de chacun des $k$-grammes de ce nom. Comme l'évaluation de la probabilité implique la multiplication des probabilités individuelles, des nombre inférieurs à 1, on préfère additionner le logarithme de celles-ci.
|
||||
|
||||
Pour calculer cette log-probabilité, on utilise aussi le lissage de Laplace, afin de tenir compte des $k$-grammes qui auraient pu ne pas apparaître lors de la création du modèle. L'équation prend la forme
|
||||
|
||||
$$
|
||||
log(p) = \sum_{i=1}^{K} log\left(\frac{C_i+1}{N_i+V}\right)
|
||||
$$
|
||||
|
||||
- $K$ est le nombre de $k$-grammes du nom.
|
||||
- $C_i$ est la fréquence du $i^{eme}$ $k$-gramme dans le modèle (origine,$k$)
|
||||
- $N_i$ est la fréquence du $i^{eme}$ ($k-1$)-gramme formé par les $k-1$ premières lettres du $k$-gramme dans le modèle (origine,$k-1$)
|
||||
- $V$ est la taille du vocabulaire, soit le nombre de caractères observés, plus le caractère de fin de mot. $V=29$ dans ce problème.
|
||||
|
||||
### Unigrammes
|
||||
On peut aussi utiliser la mesure de perplexité pour évaluer le modèle le plus probable. Dans ce cas, on utilise la mesure suivante, que l'on désire minimiser
|
||||
|
||||
### Bigrammes
|
||||
$$
|
||||
PERP = \sqrt[K]{\prod_{i=1}^{K}\left(\frac{C_i+1}{N_i+V}\right)^{-1}}
|
||||
$$
|
||||
|
||||
### Trigrammes
|
||||
En utilisant les log-probabilités, on obtient
|
||||
|
||||
$$
|
||||
PERP = \exp\left({- \frac{1}{K}\sum_{i=1}^{K} log\left(\frac{C_i+1}{N_i+V}\right)}\right)
|
||||
$$
|
||||
|
||||
### Performance des modèles
|
||||
|
||||
#### Modèles unigrammes
|
||||
|
||||
On observe qu'il n'est généralement pas possible de prédire l'origine d'un nom en considérant seulement les lettres du nom. Seul le portugais et le polonais présentent une performance acceptable.
|
||||
|
||||
![](images/2_seaborn_hm_echec_1.png)
|
||||
|
||||
#### Modèles bigrammes
|
||||
|
||||
Les bigrammes permettent d'identifier correctement les noms de quelques origines avec une bonne fiabilité. La majorité des noms sont bien classés, mais le taux d'erreur est encore élevé pour la majorité des langues. On remarque que certaines langues sont confondues entre elles (anglais-irlandais-écossais; japonais-coréen; vietnamien-chinois).
|
||||
|
||||
![](images/2_seaborn_hm_echec_2.png)
|
||||
|
||||
#### Modèles trigrammes
|
||||
|
||||
Les modèles trigrammes ont une très bonne précision pour environ la moitié des origines. On observe ici que certaines origines ne sont plus reconnues du tout, ce qui amplifie le phénomène observé avec les bigrammes. On peut poser l'hypothèse que nous avons aussi vu une quantité beaucoup moins élevé des trigrammes possibles, donc le lissage de Laplace prend beaucoup d'importance et les modèles perdent davantage en précision.
|
||||
|
||||
### Conclusion
|
||||
|
||||
Le fait d'utiliser la log-probabilité ou la perplexité n'a pas vraiment d'impact sur les résultats, pour chaque modèle, on observe une différence d'un ou deux noms classés différemment entre les deux mesures.
|
||||
|
||||
On observe que les bigrammes apportent un gain significatif au niveau de la performance de la classification, mais que les trigrammes ont tendance à faire ressortir certains excellents modèles tout en produisant d'autres modèles plutôt médiocres..
|
||||
|
||||
![](images/2_seaborn_hm_echec_3.png)
|
||||
|
||||
## Classification de textes
|
||||
|
||||
|
|
|
@ -8,7 +8,10 @@ import json
|
|||
import math
|
||||
import operator
|
||||
from functools import reduce
|
||||
import pprint
|
||||
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
import seaborn as sn
|
||||
|
||||
datafiles = "./data/names/*.txt" # les fichiers pour construire vos modèles
|
||||
test_filename = './data/test-names-t2.txt' # le fichier contenant les données de test pour évaluer vos modèles
|
||||
|
@ -190,7 +193,7 @@ def perplexity(name, origin, n=3):
|
|||
P = (C + 1) / (N + V)
|
||||
probs_name.append(P)
|
||||
|
||||
perp = math.pow(prod([1 / x for x in probs_name]), 1 / length_name)
|
||||
perp = math.exp(-sum([math.log(x) for x in probs_name]) / length_name)
|
||||
|
||||
return perp
|
||||
|
||||
|
@ -258,10 +261,22 @@ if __name__ == '__main__':
|
|||
# print("\nLes données pour tester vos modèles sont:")
|
||||
# for org, name_list in test_names.items():
|
||||
# print("\t", org, name_list)
|
||||
n = 1
|
||||
res_logprob, succ_logprob = evaluate_models(test_filename, n, True)
|
||||
res_perp, succ_perp = evaluate_models(test_filename, n, False)
|
||||
print("Avec logprob:\n")
|
||||
pprint.pprint(succ_logprob)
|
||||
print("Avec perplexité:\n")
|
||||
pprint.pprint(succ_perp)
|
||||
for n in range(1, 4):
|
||||
res_logprob, succ_logprob = evaluate_models(test_filename, n, True)
|
||||
res_perp, succ_perp = evaluate_models(test_filename, n, False)
|
||||
|
||||
print(res_logprob)
|
||||
|
||||
# Résultats pour le rapport
|
||||
|
||||
df_succ_logprob = pd.DataFrame.from_dict(succ_logprob).fillna(0).transpose()
|
||||
df_succ_logprob.columns = ['echec_logprob', 'succes_logprob']
|
||||
df_succ_perp = pd.DataFrame.from_dict(succ_perp).fillna(0).transpose()
|
||||
df_succ_perp.columns = ['echec_perp', 'succes_perp']
|
||||
df_succ = df_succ_logprob.join(df_succ_perp)
|
||||
|
||||
f, ax = plt.subplots(figsize=(9, 9))
|
||||
hm_echec = sn.heatmap(df_succ, annot=True, fmt="d", linewidths=.5, ax=ax, cmap='Oranges')
|
||||
hm_echec.set(title="Performance de modèles "+{1:"uni",2:"bi",3:"tri"}[n]+"grammes \nsur les données de test")
|
||||
plt.tight_layout()
|
||||
hm_echec.get_figure().savefig("images/2_seaborn_hm_echec_"+str(n)+".png")
|
||||
|
|
Loading…
Add table
Reference in a new issue