commit f2a4afbbb0d252db84a550268941f3fc797308a1 Author: Francois Pelletier Date: Fri Sep 20 23:44:03 2019 -0400 exercice 1 code fonctionnel 35/40 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..67ee61d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +data/ +t1_results.txt diff --git a/t1_conversion_questions.py b/t1_conversion_questions.py new file mode 100644 index 0000000..1c90c82 --- /dev/null +++ b/t1_conversion_questions.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- +import re + +questions_fn = "./data/questions-t1.txt" +results_filename = "./t1_results.txt" + + +# Mettre dans cette partie les expressions régulières +# que vous utilisez pour analyser les questions +# et en faire la conversion en affirmations +# +# Vos regex... +# + +def run_task1(filename): + questions = load_questions(filename) + results = convert_all_questions(questions) + save_results(results) + + +def convert_all_questions(questions): + results = [] + for question in questions: + sentence = convert(question) + results.append((question, sentence)) + return results + + +def load_questions(filename): + with open(filename, 'r', encoding='utf-8') as f: + raw_questions = f.readlines() + questions = [x.strip() for x in raw_questions] + return questions + + +def convert(question): + # Insérer ici votre code pour le traitement des questions et leur conversion. + # Vous pouvez ajouter autant de fonctions que vous souhaitez. + # Voir fichier data/results-reference-t1.txt pour des exemples de conversion. + # + # IMPORTANT : Ne pas modifier les autres fonctions existantes de ce fichier + # afin de faciliter mon travail de correction. + # En cas de doute, me consulter. + # Votre code... + + + regex_qui = re.compile(r"(qui)\s" + r"(est|sont|était|étaient|sera|seront|a\s\w+|ont\s\w+)\s" + r"(.*)\?", + re.IGNORECASE) + modif1 = re.sub(regex_qui, + r"Luc Lamontagne \2 \3.", + question) + + regex_questce = re.compile(r"(qu'est-ce\squ[ie'])\s?" + r"(.*)\?", + re.IGNORECASE) + modif2 = re.sub(regex_questce, r"\2 est X.", modif1) + + regex_quesont = re.compile(r"(qu[e'])\s" + r"(est|sont|signifie|fait)-?(on)?" + r"(.*)\?", + re.IGNORECASE) + modif3 = re.sub(regex_quesont, + r"\4 \3 \2 X.", + modif2) + + regex_ou = re.compile(r"((dans\squel(le)?\s(ville|région|pays))|où)\s" + r"(est|sont)\s" + r"(.*)\?", + re.IGNORECASE) + regex_capitale = re.compile(r"(quelle)(\sest\sla\scapitale)", re.IGNORECASE) + modif4 = re.sub(regex_ou, + r"\6 \5 à Québec.", + re.sub(regex_capitale, + r"où\2", modif3)) + + regex_mesure = re.compile(r"([aà]\s)?quelle\s" + r"(est\s)?" + r"(l[a']\s?)?" + r"(hauteur|température|vitesse|distance|espérance\sde\svie)\s" + r"(.*)\?", + re.IGNORECASE) + modif5 = re.sub(regex_mesure, + r"\3 \4 \5 \2 1000.", + modif4) + + regex_quelle_est = re.compile(r"quel[les]*\s(.*)(est|sont)\s(.*)\?", + re.IGNORECASE) + modif6 = re.sub(regex_quelle_est, r"\1\3 \2 X.", modif5) + + regex_quand = re.compile(r"(quand|en\squelle\sannée)\s(.*)\?", + re.IGNORECASE) + modif7 = re.sub(regex_quand, + r"\2 en 2000.", + modif6) + + regex_pourquoi = re.compile(r"pourquoi\s(.*)\?", + re.IGNORECASE) + modif8 = re.sub(regex_pourquoi, + r"\1 parce que X.", + modif7) + + regex_combien1 = re.compile(r"combien\sde\s(\w+)(.*)\?", + re.IGNORECASE) + modif9 = re.sub(regex_combien1, + r"\2 1000 \1.", + modif8) + + regex_combien2 = re.compile(r"combien\s(y\sa-t-il)?\s?de(.*)\?", + re.IGNORECASE) + modif10 = re.sub(r"\by\sa-t-il", + r"il y a", + re.sub(regex_combien2, + r"\1 1000 \2.", + modif9)) + + regex_quelle_fin = re.compile(r"(.*?)(qu\w+)\s(\w+)\?", + re.IGNORECASE) + modif11 = re.sub(regex_quelle_fin, + r"\1 \3 X.", + modif10) + + # Modifications non liées aux mots + modif12 = re.sub(r"(\w+)(-t)?-(il|elle)", r"\1", modif11) + modif12 = re.sub(r"(\w+)(-t)?-(vous)", r"\3 \1", modif12) + modif12 = re.sub(r"\s{2,}", " ", modif12) + modif12 = re.sub(r"^\s", "", modif12) + modif12 = re.sub(r"\'\s", "'", modif12) + + if question != modif11: + return modif12 + else: + return "la terre est ronde." + + +def save_results(results): + with open(results_filename, 'w') as output_file: + for question, sentence in results: + output_file.write("Q: " + question + "\n") + output_file.write("A: " + sentence + "\n") + output_file.write("\n") + + +if __name__ == '__main__': + # Vous pouvez modifier cette section + print("Conversion des questions du fichier {} ".format(questions_fn)) + run_task1(questions_fn) + print("Conversion complétée") diff --git a/t2_classification_noms.py b/t2_classification_noms.py new file mode 100644 index 0000000..9ddcc06 --- /dev/null +++ b/t2_classification_noms.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals +import glob +import os +import string +import unicodedata +import json + +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 + +names_by_origin = {} # un dictionnaire qui contient une liste de noms pour chaque langue d'origine +all_origins = [] # la liste des 18 langues d'origines de noms + +BOS = "~" # character used to pad the beginning of a name +EOS = "!" # character used to pad the end of a name + + +def find_files(path): + """Retourne le nom des fichiers contenus dans un répertoire. + glob fait le matching du nom de fichier avec un pattern - par ex. *.txt""" + return glob.glob(path) + + +def get_origin_from_filename(filename): + """Passe-passe qui retourne la langue d'origine d'un nom de fichier. + Par ex. cette fonction retourne Arabic pour "./data/names/Arabic.txt". """ + return os.path.splitext(os.path.basename(filename))[0] + + +def unicode_to_ascii(s): + """Convertion des caractères spéciaux en ascii. Par exemple, Hélène devient Helene. + Tiré d'un exemple de Pytorch. """ + all_letters = string.ascii_letters + " .,;'" + return ''.join( + c for c in unicodedata.normalize('NFD', s) + if unicodedata.category(c) != 'Mn' + and c in all_letters + ) + + +def read_names(filename): + """Retourne une liste de tous les noms contenus dans un fichier.""" + with open(filename, encoding='utf-8') as f: + names = f.read().strip().split('\n') + return [unicode_to_ascii(name) for name in names] + + +def load_names(): + """Lecture des noms et langues d'origine d'un fichier. Par la suite, + sauvegarde des noms pour chaque origine dans le dictionnaire names_by_origin.""" + for filename in find_files(datafiles): + origin = get_origin_from_filename(filename) + all_origins.append(origin) + names = read_names(filename) + names_by_origin[origin] = names + + +def train_models(): + load_names() + # Vous ajoutez à partir d'ici tout le code dont vous avez besoin + # pour construire vos modèles N-grammes pour chacune des langues d'origines. + # + # Vous pouvez ajouter au fichier toutes les fonctions que vous jugerez nécessaire. + # Merci de ne pas modifier les fonctions présentes dans ce fichier. + # + # À compléter - Fonction pour la construction des modèles unigrammes, bigrammes et trigrammes. + # + # Votre code à partir d'ici... + + +def most_probable_origin(name, n=3): + # Retourne la langue d'origine la plus probable du nom. + # n désigne la longueur des N-grammes. Par ex n=3 --> trigramme + # À compléter... + return "French" # À modifier + + +def logprob(name, origin, n=3): + # Retourne la valeur du logprob d'un nom étant donné une origine + # Utilisez une fonction logarithme en base 2. + # À compléter... + return -35.6 # À modifier + + +def perplexity(name, origin, n=3): + # Retourne la valeur de perplexité d'un nom étant donné une origine + # À compléter... + return 7.8 # À modifier + + +def load_test_names(filename): + """Retourne un dictionnaire contenant les données à utiliser pour évaluer vos modèles. + Le dictionnaire contient une liste de noms (valeurs) et leur origine (clé).""" + with open(filename, 'r') as fp: + test_data = json.load(fp) + return test_data + + +def evaluate_models(filename, n=3): + """Fonction utilitaire pour évaluer vos modèles. Aucune contrainte particulière. + Je n'utiliserai pas cette fonction pour l'évaluation de votre travail. """ + test_data = load_test_names(filename) + # À compléter - Fonction pour l'évaluation des modèles N-grammes. + # ... + + +if __name__ == '__main__': + # Vous pouvez modifier cette section comme bon vous semble + load_names() + print("Les {} langues d'origine sont:".format(len(all_origins))) + print(all_origins) + print("Les noms chinois sont:") + print(names_by_origin["Chinese"]) + + train_models() + some_name = "Lamontagne" + some_origin = most_probable_origin(some_name) + logprob = logprob(some_name, some_origin) + perplexity = perplexity(some_name, some_origin) + print("\nLangue d'origine de {}: ".format(some_name), some_origin) + print("logprob({}, {}):".format(some_name, some_origin), logprob) + print("perplexity({}, {}):".format(some_name, some_origin), perplexity) + + test_names = load_test_names(test_filename) + print("\nLes données pour tester vos modèles sont:") + for org, name_list in test_names.items(): + print("\t", org, name_list) + evaluate_models(test_filename, 3) diff --git a/t3_classification_questions.py b/t3_classification_questions.py new file mode 100644 index 0000000..e7967d8 --- /dev/null +++ b/t3_classification_questions.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +from sklearn.feature_extraction.text import CountVectorizer +from sklearn.naive_bayes import MultinomialNB + +training_questions_fn = "./data/questions-t3.txt" +test_questions_fn = "./data/test-questions-t3.txt" + + +def run_question_classification(training_fn, test_fn): + accuracy_train, accuracy_test = train_and_test_classifier(training_fn, test_fn) + print("Accuracy on training set: {0:.4f}".format(accuracy_train)) + print("Accuracy on test set: {0:.4f}".format(accuracy_test)) + + +def train_and_test_classifier(training_fn, test_fn): + questions, labels = load_dataset(training_fn) + print("Nb questions d'entraînement:", len(questions)) + test_questions, test_labels = load_dataset(test_fn) + print("Nb questions de test:", len(test_questions)) + + # Insérer ici votre code pour la classification des questions. + # Votre code... + + accuracy_train = 0.8 # A modifier + accuracy_test = 0.8 # A modifier + return accuracy_train, accuracy_test + + +def load_dataset(filename): + with open(filename) as f: + lines = f.read().splitlines() + labels, questions = zip(*[tuple(s.split(' ', 1)) for s in lines]) + return questions, labels + + +if __name__ == '__main__': + run_question_classification(training_questions_fn, test_questions_fn)