Analyser les cooccurrences d’un mot clé

A

Introduction

La fouille de texte est une méthode essentielle pour extraire des informations précieuses à partir de vastes corpus de texte. Un aspect fondamental de cette analyse est l’étude des cooccurrences à partir d’un mot clé, qui peut révéler des relations sémantiques importantes et des tendances dans le texte. Cet article, propose un script Python conçu pour analyser les cooccurrences de mots clés dans un corpus de texte.
Nous aborderons également ce qu’est une cooccurrence et l’importance de définir des segments de texte pour cette analyse.
Une des applications possible de ce script (dans une perspective de fouille de texte) vide à comparer et analyser des discours politiques. En saisissant un mot clé pertinent pour chaque discours, vous pouvez examiner comment différents orateurs abordent un même sujet et comprendre les réseaux sémantiques sous-jacents. Par exemple, comparer les cooccurrences du mot « économie » dans deux discours permet de voir les thèmes associés et de révéler des différences d’approche entre les orateurs.

Les points forts du script résident dans le fait qu’il a été testé sur un corpus de 700 articles provenant du site Europresse (que j’avais sous le coude), ce qui le rend fiable pour l’analyse de gros volumes de données. Le point faible, cependant, est que j’aurais dû tester le script avec un corpus plus restreint, comme des discours politiques, qui sont la tendance du mois de juin. Dans ce cadre, le script permet de comparer deux discours distincts et d’analyser les cooccurrences autour d’un même mot-clé. Certes, le choix du mot-clé est arbitraire, mais cela peut constituer une bonne introduction à la fouille de texte.

Pour exécuter le script dans cette configuration, il suffit d’analyser deux corpus distincts (deux fichiers texte distincts) contenant des discours politiques. La seule particularité est que la première ligne de chaque discours doit être constituée par le séparateur ****.

Définition de la cooccurrence

En linguistique, une cooccurrence se réfère à la fréquence avec laquelle deux mots apparaissent ensemble dans un segment de texte donné. Par exemple, si nous considérons le mot clé « intelligence », une cooccurrence pourrait être « intelligence artificielle » si ces deux termes apparaissent fréquemment ensemble dans le texte. La cooccurrence révèle les relations contextuelles et sémantiques entre les termes, offrant un aperçu des thèmes dominants et des sujets abordés dans le corpus.

Pour tout vous dire, ce script a été développé autour d’un corpus de 700 articles provenant du site Europresse. À l’origine, j’avais horodaté les articles pour essayer de réaliser une analyse longitudinale.
Pour cela, j’ai utilisé le script d’encodage des articles Europresse pour IRAMUTEQ, en ne gardant que les dates comme variable étoilée, notamment pour essayer de visualiser l’évolution des cooccurrences à travers le temps. Bon, je me suis un peu compliqué la tâche dès le départ et je n’arrivais pas à obtenir des résultats cohérents.
J’ai donc réduit mes ambitions. Même si l’analyse de la distribution des cooccurrences semble plutôt simpliste, la cooccurrence constitue néanmoins la plus petite unité linguistique.

Présence simultanée de deux ou plusieurs éléments ou classes d’éléments dans le même énoncé.

Importance des segments de texte

Définir des segments de texte est crucial pour l’analyse des cooccurrences. La ponctuation et d’autres marqueurs syntaxiques servent souvent à délimiter ces segments. Par exemple, dans une analyse de discours politique, chaque phrase ou paragraphe peut être considéré comme un segment. Cela permet de contextualiser les cooccurrences et d’obtenir une vision plus précise des relations entre les mots.
Dans le cas de ce script, le segment de texte est en fait le paragraphe complet de l’article de presse.
Le script utilise donc le segment de texte analysé est le paragraphe complet de chaque article, délimité par la ligne commençant par ****.
Ce séparateur ****
est utilisé pour indiquer le début d’un nouvel article, donc tout le texte entre deux séparateurs **** est considéré comme un article entier et traité comme tel. La ponctuation n’est pas utilisée pour segmenter le texte dans ce script.

Le script python pour l’analyse des cooccurrences

Ce script utilise des bibliothèques Python populaires comme NLTK pour le traitement du langage naturel et wordcloud pour la visualisation. L’utilisateur peut saisir un mot clé et le script analyse les cooccurrences de ce mot dans le corpus, génère un nuage de mots et produit un fichier CSV avec les fréquences des cooccurrences.

Fonctionnalités du script :

  1. Sélection du fichier et répertoire de sortie : L’utilisateur peut sélectionner un fichier texte et un répertoire pour sauvegarder les résultats.
  2. Saisie du mot clé : L’utilisateur saisit le mot clé à analyser.
  3. Exclusion des verbes (oui/non) de l’analyse : Je n’ai pas réussi à intégrer cette option à l’interface.
  4. Exclusion des mots qui n’auraient pas été filtrée par les stopwords.
  5. Choix du nombre de cooccurrences à afficher dans le nuage de mots.
  6. Calcul des cooccurrences : Le script calcule la fréquence des mots apparaissant à proximité du mot clé.
  7. Génération du CSV et du nuage de mots : Les résultats sont sauvegardés dans un fichier CSV (fréquence des cooccurrences trouvées) et visualisés sous forme de nuage de mots.

Un point important à souligner est que, comme vous l’avez remarqué dans l’exemple (cf. image) du corpus, je suis parti d’un fichier qui aurait nécessité un nettoyage manuel.
Mais comme je suis un peu fainéant, j’ai intégré dans l’interface la possibilité d’écarter des « aberrations » linguistiques sans devoir repasser par un nettoyage manuel du corpus (fichier texte).
Vous pouvez ainsi tester rapidement l’analyse des cooccurrences en y excluant des mots ou des lettres indésirables.

import tkinter as tk
from tkinter import filedialog, messagebox, StringVar
from tkinter.ttk import Notebook, Frame
import pandas as pd
import matplotlib.pyplot as plt
from collections import Counter
import nltk
from nltk.corpus import stopwords as nltk_stopwords
from nltk.tokenize import word_tokenize
from wordcloud import WordCloud

# Charger les ressources NLTK
nltk.download('punkt')
nltk.download('stopwords')

# Variables globales
file_path = ""
output_directory = ""
keyword = ""
custom_stopwords = []
top_n_cooccurrences = 10
total_words_processed = 0
total_articles = 0
most_frequent_cooccurrence = ""

# Initialiser la liste des stopwords avec les mots supplémentaires => vous pouvez ajouter à cette liste vos stopwords
french_stopwords = set(nltk_stopwords.words('french'))
french_stopwords.update(["encore", "plus", "cela", "entre", "si", "très", "comme"]) # vous pouvez ajouter à cette liste vos stopwords

def log_message(message):
    text_area.insert(tk.END, message + "\n")
    text_area.see(tk.END)

def open_file():
    global file_path
    file_path = filedialog.askopenfilename(title="Ouvrir un fichier texte", filetypes=(("Text files", "*.txt"),))
    if file_path:
        log_message(f"Fichier sélectionné: {file_path}")

def select_output_directory():
    global output_directory
    output_directory = filedialog.askdirectory(title="Sélectionner le Répertoire de Sortie")
    if output_directory:
        log_message(f"Répertoire de sortie sélectionné: {output_directory}")

def set_keyword():
    global keyword
    keyword = keyword_entry.get()
    if keyword:
        log_message(f"Mot-clé sélectionné: {keyword}")

def set_custom_stopwords():
    global custom_stopwords, french_stopwords
    stopwords_str = stopwords_entry.get()
    if stopwords_str:
        custom_stopwords = [word.strip().lower() for word in stopwords_str.split(',')]
        french_stopwords.update(custom_stopwords)
        log_message(f"Mots à exclure ajoutés: {', '.join(custom_stopwords)}")

def set_top_n_cooccurrences():
    global top_n_cooccurrences
    try:
        top_n_cooccurrences = int(top_n_entry.get())
        log_message(f"Nombre de co-occurrences à afficher: {top_n_cooccurrences}")
    except ValueError:
        top_n_cooccurrences = 10
        log_message(f"Valeur incorrecte pour le nombre de co-occurrences. Utilisation de la valeur par défaut: 10")

def preprocess_text(doc):
    global total_words_processed
    tokens = word_tokenize(doc)
    filtered_tokens = [token.lower() for token in tokens if token.lower().isalnum() and token.lower() not in french_stopwords]
    total_words_processed += len(filtered_tokens)
    return filtered_tokens

def read_and_preprocess_file(file_path):
    global total_articles
    articles = []
    current_article = []
    with open(file_path, 'r', encoding='utf-8') as file:
        for line in file:
            if line.startswith('****'):
                if current_article:
                    articles.append(' '.join(current_article).strip())
                    current_article = []
            else:
                current_article.append(line)
    if current_article:
        articles.append(' '.join(current_article).strip())
    total_articles = len(articles)
    return articles

def calculate_cooccurrences(articles, keyword, window_size=10):
    cooccurrence_counter = Counter()
    for article in articles:
        tokens = preprocess_text(article)
        keyword_indices = [i for i, token in enumerate(tokens) if token == keyword]
        for index in keyword_indices:
            window_start = max(0, index - window_size)
            window_end = min(len(tokens), index + window_size + 1)
            context_tokens = tokens[window_start:index] + tokens[index + 1:window_end]
            for token in context_tokens:
                if token != keyword:
                    cooccurrence_counter[token] += 1
    global most_frequent_cooccurrence
    if cooccurrence_counter:
        most_frequent_cooccurrence = cooccurrence_counter.most_common(1)[0][0]
    else:
        most_frequent_cooccurrence = "Aucune co-occurrence trouvée"
    return cooccurrence_counter

def generate_csv(cooccurrences, output_directory, keyword):
    df = pd.DataFrame(cooccurrences.items(), columns=['Cooccurrence', 'Frequency'])
    csv_path = f"{output_directory}/cooccurrences_{keyword}.csv"
    df.to_csv(csv_path, index=False)
    log_message(f"Fichier CSV généré: {csv_path}")
    return csv_path

def generate_wordcloud(cooccurrences, output_directory, keyword, top_n):
    top_cooccurrences = dict(cooccurrences.most_common(top_n))
    wordcloud = WordCloud(width=800, height=400, background_color='white').generate_from_frequencies(top_cooccurrences)
    plt.figure(figsize=(10, 5))
    plt.imshow(wordcloud, interpolation='bilinear')
    plt.axis('off')
    plt.title(f"Top {top_n} Cooccurrences for '{keyword}'")
    plt_path = f"{output_directory}/wordcloud_{keyword}.png"
    plt.savefig(plt_path, bbox_inches='tight')
    plt.show()
    log_message(f"Nuage de mots généré: {plt_path}")
    return plt_path

def process_file():
    global file_path, output_directory, keyword, top_n_cooccurrences, total_words_processed, total_articles, most_frequent_cooccurrence
    total_words_processed = 0
    total_articles = 0
    most_frequent_cooccurrence = ""
    set_keyword()
    set_custom_stopwords()
    set_top_n_cooccurrences()
    if not file_path:
        messagebox.showerror("Erreur", "Veuillez sélectionner un fichier texte.")
        return
    if not output_directory:
        messagebox.showerror("Erreur", "Veuillez sélectionner un répertoire de sortie.")
        return
    if not keyword:
        messagebox.showerror("Erreur", "Veuillez saisir un mot-clé.")
        return
    log_message("Début du traitement du fichier...")
    articles = read_and_preprocess_file(file_path)
    log_message("Fichier lu et prétraité")
    cooccurrences = calculate_cooccurrences(articles, keyword)
    log_message("Calcul des co-occurrences terminé")
    csv_path = generate_csv(cooccurrences, output_directory, keyword)
    wordcloud_path = generate_wordcloud(cooccurrences, output_directory, keyword, top_n_cooccurrences)
    info_text.set(f"Nombre de mots traités: {total_words_processed}\nNombre d'articles dans le corpus: {total_articles}\nCo-occurrence la plus fréquente: {most_frequent_cooccurrence}")
    messagebox.showinfo("Succès", f"Analyse terminée.\nFichier CSV: {csv_path}\nNuage de mots: {wordcloud_path}")
    log_message("Analyse terminée")

# Interface utilisateur
root = tk.Tk()
root.title("Analyse des Co-occurrences")
root.geometry("1000x800")
notebook = Notebook(root)
notebook.pack(expand=True, fill='both')

tab1 = Frame(notebook)
notebook.add(tab1, text="Analyse des Co-occurrences")

text_area = tk.Text(tab1, height=10, width=120)
text_area.pack(pady=5)

info_text = StringVar()
info_label = tk.Label(tab1, textvariable=info_text, justify='left')
info_label.pack(pady=5)

file_btn = tk.Button(tab1, text="Ouvrir un Fichier", command=open_file)
file_btn.pack(pady=5)
directory_btn = tk.Button(tab1, text="Sélectionner le Répertoire de Sortie", command=select_output_directory)
directory_btn.pack(pady=5)

keyword_label = tk.Label(tab1, text="Entrez le mot-clé pour l'analyse:")
keyword_label.pack(pady=5)
keyword_entry = tk.Entry(tab1)
keyword_entry.pack(pady=5)

stopwords_label = tk.Label(tab1, text="Entrez les mots à exclure supplémentaires (séparés par une virgule):")
stopwords_label.pack(pady=5)
stopwords_entry = tk.Entry(tab1)
stopwords_entry.pack(pady=5)

top_n_label = tk.Label(tab1, text="Nombre de co-occurrences à afficher:")
top_n_label.pack(pady=5)
top_n_entry = tk.Entry(tab1)
top_n_entry.pack(pady=5)

process_btn = tk.Button(tab1, text="Traiter le Fichier et Générer les Résultats", command=process_file)
process_btn.pack(pady=5)

link_label = tk.Label(tab1, text="www.codeandcortex.fr", fg="white", cursor="hand2")
link_label.pack(pady=5)
link_label.bind("<Button-1>", lambda e: open_url("https://www.codeandcortex.fr"))

def open_url(url):
    import webbrowser
    webbrowser.open_new(url)

root.mainloop()

 

Conclusion et perspectives

Il n’est pas absolument nécessaire d’utiliser NLTK pour calculer les cooccurrences.
Bien que NLTK soit une bibliothèque puissante et polyvalente pour le traitement du langage naturel, il existe d’autres outils et bibliothèques qui peuvent également être utilisés pour cette tâche, tels que:

  1. Pandas : Pour manipuler et analyser des données structurées (amplement suffisant).
  2. spaCy : Pour un traitement du langage naturel.
  3. gensim : Spécialement conçu pour le traitement de grands corpus de texte.
  4. Bert (CamenBERT, la version fr développée par l’INRIA)

Ainsi, dans la continuité du script faisant l’analyse des cooccurrences, je vais travailler sur l’analyse de similarité lexicale basée sur les cooccurrences et une analyse de similarité sémantique sur des segments de texte.
Cette approche, utilisera un test de similarité cosinus (Le test de similarité cosinus est une mesure de similarité entre deux vecteurs dans un espace vectoriel, qui quantifie la différence angulaire entre eux), reposant sur un modèle de traitement de langage naturel comme Spacy ou BERT, avec des outils comme la tokenisation, le POS tagging (annotation des mots avec leur catégorie grammaticale : nom, verbe, adjectif, etc.), le stemming, la lemmatisation,…

A propos de l'auteur

Stéphane Meurisse

Ajouter un commentaire

Stéphane Meurisse