chargement...

Les Scripts

de type python, shell.

PPE2 pluriTAL.

Les scripts

Les scripts se divisent principalement en 4 parties:

  • Le script utilisé pour la création du dictionnaire(Petit exercice jusqu'à la semaine 3)
  • Scripts de modules, de fonctions et de classes
  • Script main (qui permet de lancer les scripts précédents)
  • Script LDA (qui permet de faire le traitement LDA et de générer les visualisations associées))




  • Le script utilisé pour la création du dictionnaire

    Ce script est une intégration des réalisations des trois premières semaines de travail, qui permet de traiter des fichiers texte. Il utilise des arguments de ligne de commande pour spécifier les chemins des fichiers.

    L'argument --chemin est utilisé pour spécifier les chemins des fichiers. Il définit des fonctions construit_liste_de_chaines, construit_liste_de_chaines_r2_r3 , count_words , doc_freq et lexique qui permettent de compter la fréquence des mots et la fréquence des documents, et de générer un lexique.

    Script
    
    ###################################### Partie r1
    import sys
    import argparse
    parser = argparse.ArgumentParser(
        description="Obtenir un argument par bash command, un argument qui indique le chemin des fichiers")
    parser.add_argument('--chemin', type=str, nargs='+',
                        help='le chemin relatif des fichiers')
    args = parser.parse_args()
    
    def construit_liste_de_chaines(corpus_path):
        list_contenu = []
        for txtname in (corpus_path):
            with open(txtname, 'r') as file:
                data = file.read()
                list_contenu.append(data)
        return list_contenu
    
    ###################################### Partie r2 & r3
    def construit_liste_de_chaines_r2_r3():
        list_contenu = []
        for txtname in sys.stdin:
            if txtname.endswith('.txt'):
                ## r3
                txtname = txtname.replace('\n', '')
                with open(txtname, 'r') as file:
                    data = file.read()
                    list_contenu.append(data)
            else:
                ## r2
                list_contenu.append(txtname)
        
        return list_contenu
    
    
    def count_words(corpus_list):
        dictionnaire_freq = {}
        for sing_contenu in corpus_list:
            mots = sing_contenu.split()
            for mot in mots:
                if mot in dictionnaire_freq:
                    dictionnaire_freq[mot] += 1
                else:
                    dictionnaire_freq[mot] = 1
        return dictionnaire_freq
    
    
    def doc_freq(corpus):
        nb_doc = {}
        for doc in corpus:
            words = set(doc.split())
            for word in words:
                if word in nb_doc:
                    nb_doc[word] += 1
                else:
                    nb_doc[word] = 1
        return nb_doc
    
    
    def lexique():
        liste_gros = []
        if (args.chemin == None):
            # r2 & r3
            liste_gros = construit_liste_de_chaines_r2_r3()
        elif (isinstance(args.chemin, list)):
            # r1
            liste_gros = construit_liste_de_chaines(args.chemin)
    
        dict_freq = count_words(liste_gros)
        dict_occurence = doc_freq(liste_gros)
        len_liste_final = len(dict_freq)
        for i in range(len_liste_final):
            key = list(dict_freq)[i]
            value1 = list(dict_freq.values())[i]
            value2 = list(dict_occurence.values())[i]
            print("{0:^20}|{1:^20}|{2:^20}".format(key, value1, value2))
    
    
    if __name__ == '__main__':
        lexique()
                                           
                                      

    Scripts de modules, de fonctions et de classes

    Il est possible d'utiliser les fonctions déjà définies pour exécuter des tâches ou des opérations spécifiques dans la fonction principale. En séparant ces fonctions de la fonction principale, on peut mieux organiser le code et améliorer sa lisibilité et sa maintenabilité.

    1. Scripts de parser : etree et re

    Ce script contient des fonctions qui sont responsables de l'analyse de fichiers XML et de l'extraction d'informations à partir de texte à l'aide d'expressions régulières. Le script "etree" utilise le module "xml.etree.ElementTree" pour le parsing des fichiers XML, tandis que le script "re" utilise des expressions régulières pour extraire des informations d'un texte. Les deux fonctions peuvent être appelés en tant que modules.

    Script
    
    # parser avec module "etree"                
    import xml.etree.ElementTree as ET
    
    
    # Objectif : extraire et afficher le titre et la description de chaque article dans un fichier XML.
    
    # deuxieme choix : module "etree" avec argparse
    # Si le fichier est importé en tant que module, la fonction title_descr peut être appelée directement
    def etree_parser(xml):
        tree = ET.parse(xml)
        root = tree.getroot()
        for article in root.findall(".//item"):
            title = article.find('title').text
            description = article.find('description').text
            yield title, description
    
    # ------------------------------------------------------------------------------------------------------------------------------
    
    # parser module "re"
    import re
    from pathlib import Path
    
    # Objectif : extraire et afficher le titre et la description de chaque article dans un fichier XML.
    # Si le fichier est importé en tant que module, la fonction title_descr peut être appelée directement
    
    def re_parser(fic):
        fic_path = Path(fic)
        xml = fic_path.read_text()
        # 1. trouver chaque article comme un élément dans une liste
        art_pattern = re.compile('.*?')
        art_liste = art_pattern.findall(xml)
        # 2. dans chaque article, trouver son titre et description
        for article in art_liste:
            tit_pattern = re.compile(r"<!\[CDATA\[(.*?)\]\]>")
            titre = tit_pattern.search(article).group(1)
            desc_pattern = re.compile(
                r"")
            description = desc_pattern.search(article).group(1)
            yield titre, description
                                                      
    2. Dataclass

    Ce script définit plusieurs classes de données qui permettent de créer des objets avec des attributs pré-définis. Les classes définies dans ce script utilisent le décorateur @dataclass pour créer des objets avec des attributs pré-définis. Ici, ces trois classes permettent de structurer les données d'un corpus textuel avec des articles, des analyses linguistiques et des informations associées. Elles facilitent la manipulation et l'accès aux données, ainsi que la gestion de la structure hiérarchique des données.

    Script
    
    from typing import List, Optional
    from dataclasses import dataclass
    from pathlib import Path
    
    
    @dataclass
    class Analyse:
        form: str
        lemma: str
        pos: str
    
    
    @dataclass
    class Article:
        title: str
        desc: str
        date: str
        categorie: str
        analyse: Optional[List[Analyse]] = None
    
    
    @dataclass
    class Corpus:
        cat: List[str]
        start: str
        end: str
        path: Path
        content: List[Article]                           
                                      
    3. Exports

    write_json : Cette fonction prend un objet Corpus et un chemin de destination en paramètres. Elle utilise la fonction asdict pour convertir l'objet Corpus en un dictionnaire Python, puis utilise json.dump pour écrire ce dictionnaire dans un fichier JSON. Cela permet de sauvegarder les données des classes dataclass dans un format JSON.

    article_to_xml : Cette fonction prend un objet Article en paramètre et renvoie un élément XML correspondant à cet article. Elle crée un élément "article" et attribue les valeurs des attributs date et categorie. Elle crée également des éléments "title", "description" et "analyse" avec leurs valeurs respectives. Si l'article contient des analyses, elle crée des éléments "token" pour chaque analyse avec les attributs "form", "lemma" et "pos". Ensuite, elle renvoie l'élément XML de l'article.

    write_xml : Cette fonction prend un objet Corpus et un chemin de destination en paramètres. Elle crée un élément "corpus" et attribue les valeurs des attributs start et end. Elle crée également un élément "categories" et un élément "content". Pour chaque catégorie du corpus, elle crée un élément "cat" sous l'élément "categories". Pour chaque article du corpus, elle utilise la fonction article_to_xml pour obtenir l'élément XML correspondant, puis l'ajoute à l'élément "content". Enfin, elle crée un objet ElementTree à partir de l'élément "corpus", applique l'indentation et écrit le résultat dans un fichier XML à l'aide de la méthode write.

    Ces fonctions permettent de convertir les données des classes dataclass en formats JSON et XML pour la sauvegarde ou l'échange de données.

    Script
    
    import json
    from dataclasses import asdict
    from xml.etree import ElementTree as ET
    from datastructures import Corpus, Article, Analyse
    
    
    # fonction pour sortir les données de dataclasses en json
    def write_json(corpus: Corpus, destination: str):
        with open(destination, "w", encoding='utf-8') as fout:
            json.dump(asdict(corpus), fout, ensure_ascii=False, indent=2)
    
    # fonction pour sortir les données de dataclasses en xml
    
    def article_to_xml(article: Article) -> ET.Element:
        xml_article = ET.Element("article")
        xml_article.attrib['date'] = article.date
        xml_article.attrib['categorie'] = article.categorie
        title = ET.SubElement(xml_article, "title")
        description = ET.SubElement(xml_article, "description")
        analyses = ET.SubElement(xml_article, "analyse")
        title.text = article.title
        description.text = article.desc
        for analyse in article.analyse:
            token = ET.SubElement(analyses, "token")
            token.attrib['form'] = analyse.form
            if analyse.pos and analyse.lemma is not None:
                token.attrib['lemma'] = analyse.lemma
                token.attrib['pos'] = analyse.pos
            else:
                token.attrib['lemma'] = "null"
                token.attrib['pos'] = "null"
                print(
                    f"Attention: l'analyse pos du mot '{analyse.form}' renvoie null, skipping...")
        return xml_article
    
    # fonction pour sortir les données de dataclasses en xml
    
    def write_xml(corpus: Corpus, destination: str):
        root = ET.Element("corpus")
        root.attrib['start'] = corpus.start
        root.attrib['end'] = corpus.end
        categories = ET.SubElement(root, "categories")
        for c in corpus.cat:
            ET.SubElement(categories, "cat").text = c
    
        content = ET.SubElement(root, "content")
        for article in corpus.content:
            art_xml = article_to_xml(article)
            content.append(art_xml)
    
        tree = ET.ElementTree(root)
        ET.indent(tree)
        tree.write(destination, encoding='utf-8', xml_declaration=True)                                              
                                      
    4. TAL modules

    Ces fonctions fournissent un choix de modules NLP différents pour effectuer des analyses et des traitements de texte. Selon les besoins, vous pouvez choisir le module qui convient le mieux. Chaque fonction prend un texte en entrée et renvoie un dictionnaire contenant des informations sur la lemmatisation et l'annotation grammaticale des mots. Ces informations peuvent être utilisées pour des tâches et des analyses LDA ultérieures.

    Script
    
    # arsenal of NLP modules
    import spacy
    import trankit
    import stanza
    
    
    def trankit_parser():
        return trankit.Pipeline('french', gpu=False)
    
    
    def trankit_analyse(parser, text: str):
        desc_analyse = {}
        fr_output = parser.posdep(text)
        lemma_doc = parser.lemmatize(text)
        for x in lemma_doc.get('sentences'):
            for token in x.get('tokens'):
                analyse_contenu = []
                analyse_contenu.append(token.get('lemma'))
                for y in fr_output.get('sentences'):
                    for token2 in y.get('tokens'):
                        if token2.get('text') == token.get('text'):
                            analyse_contenu.append(token2.get('upos'))
                desc_analyse[token.get('text')] = analyse_contenu
        return desc_analyse
    
    
    def spacy_parser():
        return spacy.load("fr_core_news_sm")
    
    
    def spacy_analyse(parser, text: str):
        doc = parser(text)
        desc_analyse = {}
        for token in doc:
            analyse_contenu = []
            analyse_contenu.append(token.lemma_)
            analyse_contenu.append(token.pos_)
            desc_analyse[token.text] = analyse_contenu
        return desc_analyse
    
    
    def stanza_parser():
        return stanza.Pipeline('fr')
    
    
    def stanza_analyse(parser, text: str):
        doc = parser(text)
        desc_analyse = {}
        for sent in doc.sentences:
            for word in sent.words:
                analyse_contenu = []
                analyse_contenu.append(word.lemma)
                analyse_contenu.append(word.upos)
                desc_analyse[word.text] = analyse_contenu
        return desc_analyse                                       
                                      

    "main.py"

    le main script

    Le script principal parcourt les fichiers XML correspondant à certaines catégories et périodes spécifiées, extrait les titres et descriptions des articles, effectue une analyse linguistique à l'aide d'un module NLP, puis enregistre ou affiche les résultats en fonction des options choisies.

    Il importe les modules nécessaires et définit des constantes, telles que les mois et les jours, qui seront utilisées ultérieurement. Ensuite, il définit un dictionnaire qui associe des codes de catégories à leurs noms correspondants.

    Ensuite, le script parcourt les fichiers XML dans un répertoire donné, en tenant compte des critères tels que les catégories, la date de début et la date de fin. Cette fonction renvoie un générateur qui produit un par un les fichiers XML répondant aux critères spécifiés.

    Pour chaque fichier retourné, il extrait le titre et la description à l'aide de la fonction fonc. Si ces informations sont valides, un objet Article est créé et ajouté au corpus. Le script utilise également un module NLP spécifié pour effectuer une analyse du titre et de la description. Les informations obtenues, telles que les lemmes et les étiquettes de partie du discours, sont associées à chaque mot et ajoutées à l'objet Article. Enfin, en fonction des arguments de ligne de commande, le script écrit les résultats dans un fichier de sortie au format JSON, XML ou pickle, ou les affiche simplement dans la console.

    Script
    
    from title_descr_re import re_parser
    from title_descr_etree import etree_parser
    import re
    from xml.etree import ElementTree as et
    import argparse
    import sys
    from typing import Optional, List, Dict
    from datetime import date
    from pathlib import Path
    import pickle
    from datastructures import Corpus, Article, Analyse
    from exports import write_json, write_xml
    import nlp_modules
    from tqdm import tqdm
    import gensim_lda_pred as lda
    
    
    # Objectif : parcourir les fichiers et, extraire et afficher le titre et la description de chaque article correspondant à une catégorie
    MONTHS = ["Jan",
              "Feb",
              "Mar",
              "Apr",
              "May",
              "Jun",
              "Jul",
              "Aug",
              "Sep",
              "Oct",
              "Nov",
              "Dec"]
    
    DAYS = [f"{x:02}" for x in range(1, 32)]
    
    
    cat_dict = {
        'une': '0,2-3208,1-0,0',
        'international': '0,2-3210,1-0,0',
        'europe': '0,2-3214,1-0,0',
        'societe': '0,2-3224,1-0,0',
        'idees': '0,2-3232,1-0,0',
        'economie': '0,2-3234,1-0,0',
        'actualite-medias': '0,2-3236,1-0,0',
        'sport': '0,2-3242,1-0,0',
        'planete': '0,2-3244,1-0,0',
        'culture': '0,2-3246,1-0,0',
        'livres': '0,2-3260,1-0,0',
        'cinema': '0,2-3476,1-0,0',
        'voyage': '0,2-3546,1-0,0',
        'technologies': '0,2-651865,1-0,0',
        'politique': '0,57-0,64-823353,0',
        'sciences': 'env_sciences',
    }
    
    
    def categorie_of_ficname(ficname: str) -> Optional[str]:
        for nom, code in cat_dict.items():
            if code in ficname:
                return nom
        return None
    
    
    def convert_month(mon: str) -> int:
        m = MONTHS.index(mon) + 1
        return m
    
        # Etape 2 : filtrer les fichiers selon les exigences, répondant aux critères suivants  :
        # 1. les fichiers sont au format XML, placés dans un dossier Corpus/Mmm/JJ/19-00-00/
        # 2. les fichiers sont de bonne période et de bonne(s) catégorie(s).
        # 3. les fichiers XML comme "fil1646762506-v1.xml" doivent être exclus. Les fichiers attendus doivent avoir leur code de categorie dans leur nom
    
        # La fonction 'parcours_path' prend en entrée un répertoire corpus_dir et plusieurs arguments optionnels
        # Elle itère sur chaque fichier XML dans le répertoire et renvoie un générateur qui produit un par un les fichiers XML qui répondent aux critères spécifiés.
    
    
    def parcours_path(corpus_dir: Path, categories: Optional[List[str]] = None, start_date: Optional[date] = None, end_date: Optional[date] = None):
        if categories is not None and len(categories) > 0:
            # 对于所有在categories列表里的c,我们依次在cat-code里找出其对应的答案
            categories = [cat_dict[c] for c in categories]
        else:
            categories = cat_dict.values()  # on prend tout
    
        for month_dir in corpus_dir.iterdir():
            if month_dir.name not in MONTHS:
                # on ignore les dossiers qui ne sont pas des mois
                continue  # 跳出这次循环,进行下一个month_dir的判断
            m_num = convert_month(month_dir.name)  # 对于Jan,我们将其对应到数字形式 m_num = 1
            for day_dir in month_dir.iterdir():
                if day_dir.name not in DAYS:
                    # on ignore les dossiers qui ne sont pas des jours    2022-07-21  2022-09-13
                    continue
                # selon le format "2022-01-25",on 生成对应的date对象
                d = date.fromisoformat(f"2022-{m_num:02}-{day_dir.name}")
                if (start_date is None or start_date <= d) and (end_date is None or end_date >= d):  # 保证该日期符合在开始和结束日期之间。
                    for time_dir in day_dir.iterdir():
                        if re.match(r"\d\d-\d\d-\d\d", time_dir.name):  # 对应19-00-00
                            for fic in time_dir.iterdir():
                                # 进一步过滤xml文件的名称
                                if fic.name.endswith(".xml") and any([c in fic.name for c in categories]):
                                    # un générateur qui produit un par un les fichiers XML qui répondent aux critères spécifiés.
                                    c = categorie_of_ficname(fic.name)
                                    yield(fic, str(d), c)
    
    
    if __name__ == "__main__":
        # Etape 1 : obtenir les fichiers d'après l'input
        parser = argparse.ArgumentParser(
            description="le script sert à extraire et afficher le titre et la description de chaque article dans un fichier XML")
        parser.add_argument(
            "-m", help="méthode de parsing (etree ou re)", default="etree")
        parser.add_argument(
            "-s", help="start date (iso format)", default="2022-06-15")
        parser.add_argument("-e", help="end date (iso format)",
                            default="2022-09-01")
        parser.add_argument("-o", help="output file (stdout if not specified")
        parser.add_argument(
            "corpus_dir", help="root dir of the corpus data,qui contient des dossiers/fichiers xml")
        parser.add_argument("categories", nargs="*",
                            help="la ou les catégories des fichiers XML désirés")
        args = parser.parse_args()
        if args.m == 'etree':
            fonc = etree_parser
            print("vous avez choisi etree pour parser")
        elif args.m == 're':
            fonc = re_parser
            print("vous avez choisi re pour parser")
        else:
            print("méthode non disponible", file=sys.stderr)
            sys.exit()
        # f = un fichier xml, obtenu par yield, soit le "yield(fic)"
    
        # creation du corpus
        tk_parser = nlp_modules.create_parser()
        print('l\'analyse commence, veuillez patienter...')
        corpus = Corpus(args.categories, args.s, args.e, args.corpus_dir, [])
        for f, dt, c in tqdm(parcours_path(Path(args.corpus_dir),
                                            start_date=date.fromisoformat(args.s),
                                            end_date=date.fromisoformat(args.e),
                                            categories=args.categories)):
            for title, desc in tqdm(fonc(f)):
                if title and desc is not None:
                    article = Article(title, desc, dt, c, [])
                    corpus.content.append(article)
                    analyse_dict = nlp_modules.trankit_analyse(
                        tk_parser, title + " " + desc)
                    for forme in analyse_dict:
                        token = Analyse(forme, analyse_dict.get(forme)[
                            0], analyse_dict.get(forme)[1])
                        article.analyse.append(token)
          # d'après le format de fichier de sortie, on écrit le résultat dans le fichier correspondant
        if args.o.endswith(".js"):
            print('parsing done, outputed in the file de format json you required')
            write_json(corpus, args.o)
    
        # output xml
        elif args.o.endswith(".xml"):
            print('parsing done, outputed in the xml file you required')
            write_xml(corpus, args.o)
    
        elif args.o.endswith(".pickle"):
            print(
                'parsing done, outputed in the file pickle you required, may not that visible')
            with open(args.o, 'wb') as f:
                pickle.dump(corpus, f)
            with open(args.o, 'rb') as r:
                returned_data = pickle.load(r)
    
        else:
            print('parsing done, outputed in the terminal')
            for f in parcours_path(Path(args.corpus_dir),
                                    start_date=date.fromisoformat(args.s),
                                    end_date=date.fromisoformat(args.e),
                                    categories=args.categories):
                for title, desc in fonc(f):
                    if title and desc is not None:
                        print(">>> Titre:", title)
                        print(">>> Description:", desc)
                        print(
                            '------------------------------------------------------------------------------------------------------------------------------')
                  

    Pour utiliser ce script dans le terminal :

    python pluri_extraire(avec analyse).py -m etree -s 2022-07-01 -e 2022-09-30 -o international_s3.xml 2022 sport -p spacy
    # Pour extraire avec etree et obtenir un fichier dont le nom est "international_s3.xml", cat=sport, analyse avec spacy, d'une période 2022-07-01 ---- 2022-09-30
    LDA Topic Modeling

    Ce script charge un corpus de documents à partir d'un fichier XML, JSON ou pickle, prétraite les données en supprimant les mots vides et en identifiant les bigrammes, crée un modèle LDA à partir des documents prétraités, évalue la cohérence des sujets générés et génère une visualisation interactive des sujets.

    Le script effectue une étape de nettoyage des données en supprimant les mots vides (stopwords) du corpus, en utilisant une liste de mots vides prédéfinie pour le français, ainsi qu'une liste personnalisée provenant d'un fichier texte. Ensuite, le script identifie les bigrammes dans les documents à l'aide du module Phrases de gensim.

    Ensuite, le script crée un dictionnaire à partir des documents prétraités et filtre les termes extrêmes (trop fréquents ou trop rares) du dictionnaire. Le script convertit ensuite les documents prétraités en une représentation de type "sac de mots" (bag-of-words) à l'aide du dictionnaire créé précédemment.

    Après les opérations sur le dataset, le modèle LDA est entraîné en utilisant les paramètres spécifiés tels que le nombre de sujets, la taille du lot (chunksize), le nombre de passages (passes) et le nombre d'itérations. Après l'entraînement, le script évalue la cohérence des sujets générés à l'aide de la mesure de cohérence des sujets et affiche les sujets triés par ordre de cohérence.

    Enfin, le script génère une visualisation interactive des sujets à l'aide de la bibliothèque pyLDAvis, et sauvegarde la visualisation sous la forme d'un fichier HTML. En résumé, ce script charge un corpus de documents à partir d'un fichier XML, JSON ou pickle, prétraite les données en supprimant les mots vides et en identifiant les bigrammes, crée un modèle LDA à partir des documents prétraités, évalue la cohérence des sujets générés et génère une visualisation interactive des sujets.

    Script
    
    import pickle
    from pprint import pprint
    from gensim.models import LdaModel
    from gensim.corpora import Dictionary
    from gensim.models import Phrases
    from nltk.stem.wordnet import WordNetLemmatizer
    from nltk.corpus import stopwords
    import json
    from xml.etree import ElementTree as ET
    import argparse
    import logging
    import pyLDAvis.gensim_models
    import sys
    logging.basicConfig(
        format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
    
    
    def load_file_xml(xml_file, type, pos=[]):
        tree = ET.parse(xml_file)
        root = tree.getroot()
        # corpus
        corpus = []
        for analyse in root.iter('analyse'):
            single_article = []
            for token in analyse.iter('token'):
                if pos == []:
                    token_1 = token.get(type)  # type = lemma / forme
                    if token_1 is not None:
                        single_article.append(token_1)
                else:
                    if token.get('pos') in pos:
                        token_1 = token.get(type)
                        if token_1 is not None:
                            single_article.append(token_1)
            corpus.append(single_article)
        return corpus
    
    
    def load_file_json(json_file, type, pos=[]):
        with open(json_file, 'r') as f:
            data = json.load(f)
        corpus = []
        for article in data['content']:
            single_article = []
            for token in article['analyse']:
                if pos == []:
                    token_1 = token[type]
                    if token_1 is not None:
                        single_article.append(token_1)
                elif token.get('pos') in pos:
                    token_1 = token[type]
                    if token_1 is not None:
                        single_article.append(token_1)
            corpus.append(single_article)
        return corpus
    
    
    def load_file_pickle(pickle_file, type, pos=[]):
        with open(pickle_file, 'rb') as f:
            data = pickle.load(f)
        corpus = []
        for article in data.content:
            single_article = []
            for token in article.analyse:
                if pos == []:
                    token_1 = token.__getattribute__(type)
                    if token_1 is not None:
                        single_article.append(token_1)
                elif token.pos in pos:
                    token_1 = token.__getattribute__(type)
                    if token_1 is not None:
                        single_article.append(token_1)
            corpus.append(single_article)
        return corpus
    
    
    # stopwords
    def stop_words(corpus):
        with open('stopwords-fr.txt', 'r', encoding='utf-8') as f:
            sw_file = set(f.read().split())
        stop_words = set(stopwords.words('french')).union(sw_file)
        print(stop_words)
        corpus = [[word for word in doc if word not in stop_words]
                  for doc in corpus]
        return corpus
    
    
    def bigram(docs):
        bigram = Phrases(docs, min_count=10)
        for idx in range(len(docs)):
            for token in bigram[docs[idx]]:
                if '_' in token:
                    # Token is a bigram, add to document.
                    docs[idx].append(token)
        return docs
    
    
    # Create a dictionary representation of the documents.
    def filter_extremes(docs):
        dictionary = Dictionary(docs)
        dictionary.filter_extremes(no_below=5, no_above=0.9)
        return dictionary
    
    
    # Bag-of-words representation of the documents.
    def doc2bow(docs, dictionary):
        corpus = [dictionary.doc2bow(doc) for doc in docs]
        return corpus
    
    
    ###############################################################################
    # Training
    # Set training parameters.
    def train_lda_model(corpus, dictionary, num_topics=20, chunksize=2000, passes=20, iterations=400, eval_every=None):
        # Make a index to word dictionary.
        temp = dictionary[0]  # This is only to "load" the dictionary.
        id2word = dictionary.id2token
        model = LdaModel(
            corpus=corpus,
            id2word=id2word,
            chunksize=chunksize,
            alpha='auto',
            eta='auto',
            iterations=iterations,
            num_topics=num_topics,
            passes=passes,
            eval_every=eval_every
        )
        return model
    
    ###############################################################################
    # average topic coherence and print the topics in order of topic coherence.
    def topic_coherence(model, corpus, num_topics=20):
        top_topics = model.top_topics(corpus)
        avg_topic_coherence = sum([t[1] for t in top_topics]) / num_topics
        print('Average topic coherence: %.4f.' % avg_topic_coherence)
        pprint(top_topics)
        return avg_topic_coherence, top_topics
    
    # Average topic coherence is the sum of topic coherences of all topics, divided by the number of topics.
    
    
    ###############################################################################
    
    if __name__ == "__main__":
        parser = argparse.ArgumentParser(
            description="Ce script permet de créer un modèle LDA à partir d'un corpus, et de prédire les topics d'un nouveau document")
        parser.add_argument("-s", help="input file")
        parser.add_argument(
            "-m", choices=['xml', 'json', 'pickle'], help='Type of input file')
        parser.add_argument(
            "-t", help="choisir le lemma ou la forme")
        parser.add_argument(
            "pos", nargs="*", help="determiner les pos (une liste)")
        parser.add_argument("-n", help="num_topics", default=10)
        parser.add_argument("-c", help="chunksize", default=2000)
        parser.add_argument("-p", help="passes", default=20)
        parser.add_argument("-i", help="iterations", default=400)
        args = parser.parse_args()
        if args.s:
            if args.m == 'xml':
                corpus = load_file_xml(args.s, args.t, args.pos)
            elif args.m == 'json':
                corpus = load_file_json(args.s, args.t, args.pos)
            elif args.m == 'pickle':
                corpus = load_file_pickle(args.s, args.t, args.pos)
            else:
                print('Invalid filetype')
                sys.exit(1)
            corpus = stop_words(corpus)
            corpus = [[token for token in doc if not token.isnumeric()]
                      for doc in corpus]
            docs_c = [[token for token in doc if len(token) > 1] for doc in corpus]
            bi_docs = bigram(docs_c)
            dictionnaire = filter_extremes(bi_docs)
            print(dictionnaire)
            doc_bow = doc2bow(bi_docs, dictionnaire)
            print('Number of unique tokens: %d' % len(dictionnaire))
            print('Number of documents: %d' % len(doc_bow))
            num_topics = args.n
            chunksize = args.c
            passes = args.p
            iterations = args.i
            eval_every = None
            model = train_lda_model(
                doc_bow, dictionnaire, num_topics=num_topics, chunksize=chunksize, passes=passes, eval_every=eval_every)
            topic_coherence(model, doc_bow, num_topics=num_topics)
            lda_dp = pyLDAvis.gensim_models.prepare(
                model, doc_bow, dictionnaire)
            pyLDAvis.save_html(lda_dp, 'lda_dp.html')                                               
                                      

    Pour utiliser ce script dans le terminal :

    python gensim_lda_pred.py -s sous_corpus/international_s4.xml -t lemma pos NOUN -m xml -n 10
                            Scripts