<jupyter_start><jupyter_text>Imports<jupyter_code>import collections
import os
import string
import sys

import pandas as pd
from nltk import word_tokenize
from nltk.corpus import stopwords
from nltk.tokenize import wordpunct_tokenize
from unidecode import unidecode
from pprint import pprint
from sklearn.cluster import KMeans
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.decomposition import PCA
import numpy as np
import matplotlib.pyplot as plt
from scipy.spatial.distance import cosine
from collections import Counter
from wordcloud import WordCloud
from IPython.display import Image

from gensim.models.phrases import Phrases, Phraser
from gensim.models import Word2Vec
import nltk

nltk.download('punkt')<jupyter_output>[nltk_data] Downloading package punkt to /root/nltk_data...
[nltk_data]   Package punkt is already up-to-date!<jupyter_text>1. Clustering de documents de 1960 à 1969<jupyter_code>data_path = "../data/txt/"
txt_path = "../data/txt"
#choisir une décénnie
DECADE = '1960'

# Charger tous les  fichiers de la décennie et en créer une liste de textes
files = [f for f in sorted(os.listdir(data_path)) if f"_{DECADE[:-1]}" in f]
texts = [open(data_path + f).read() for f in files]<jupyter_output><empty_output><jupyter_text>Vectoriser les documents à l'aide de TF-IDF<jupyter_code># Création d'une fonction de pré-traitement
def preprocessing(text, stem=True):
    """ Tokenize text and remove punctuation """
    text = text.translate(string.punctuation)
    tokens = word_tokenize(text)
    return tokens

# Instancier le modèle TF-IDF avec ses arguments
vectorizer1 = TfidfVectorizer(
    tokenizer=preprocessing,
    stop_words = stopwords.words("french"),
    max_df=0.5,
    min_df=0.1,
    lowercase=True)

# Construire la matrice de vecteurs à l'aide de la fonction `fit_transform`
%time tfidf_vectors1 = vectorizer1.fit_transform(texts)<jupyter_output>CPU times: user 3min 30s, sys: 0 ns, total: 3min 30s
Wall time: 3min 30s<jupyter_text>Appliquer un algorithme de clustering sur les vecteurs TF-IDF des documents<jupyter_code># Définir un nombre de clusters
N_CLUSTERS = 3

# Instancier le modèle K-Means et ses arguments
km_model1 = KMeans(n_clusters=N_CLUSTERS)

# Appliquer le clustering à l'aide de la fonction `fit_predict`
clusters1 = km_model1.fit_predict(tfidf_vectors1)

clustering1 = collections.defaultdict(list)

for idx, label in enumerate(clusters1):
    clustering1[label].append(files[idx])<jupyter_output><empty_output><jupyter_text>Visualiser les clusters<jupyter_code>pca1 = PCA(n_components=2)
reduced_vectors1 = pca1.fit_transform(tfidf_vectors1.toarray())

# Générer le plot
x_axis1 = reduced_vectors1[:, 0]
y_axis1 = reduced_vectors1[:, 1]

plt.figure(figsize=(10,10))
scatter1 = plt.scatter(x_axis1, y_axis1, s=100, c=clusters1)

# Ajouter les centroïdes
centroids1 = pca1.transform(km_model1.cluster_centers_)
plt.scatter(centroids1[:, 0], centroids1[:, 1],  marker = "x", s=100, linewidths = 2, color='black')

# Ajouter la légende
plt.legend(handles=scatter1.legend_elements()[0], labels=set(clusters1), title="Clusters")<jupyter_output><empty_output><jupyter_text>2. Analyse du Term Frequency (TF)  Sortir la liste des mots les plus fréquents au travers de tous les documents de la décénnie<jupyter_code># Stocker le contenu des fichiers de la décénnie dans une liste
content_list = []
for txt in files:
    with open(os.path.join(txt_path, txt), 'r') as f:
        content_list.append(f.read())

# Ecrire tout le contenu dans un fichier temporaire
temp_path = '../data/tmp'
if not os.path.exists(temp_path):
    os.mkdir(temp_path)
with open(os.path.join(temp_path, f'frequence.txt'), 'w') as f:
    f.write(' '.join(content_list))   
    
#Afficher les 100 termes les plus fréquents
with open(os.path.join(temp_path, f'frequence.txt'), 'r') as f:
    cluster_0 = f.read()
frequencies = Counter(cluster_0.split())
print(frequencies.most_common(300))


# Mettre les mots les plus fréquents dans une liste de Stopwords 
sw = stopwords.words("french")
sw += ["de", "e", "i", "n", "r", "a", "s", "l", ".", "la", "o", "t", "é", "u", "à", "—", "m", 
       "et", "des", "le", "du", "d", "c", "en", "les", "m", "que", "p", ",", "'", "van", "pour", 
       "v", "par", "au", "e", "qui", "est", "g", "dans", "une", "pas", "un", "ce", "c", "l", "a", "1", 
       "het", ";", ":", "je", "ne", "b", "i,", "h", "nous", "q", "-", "sur", "V", "aux", "y", "è", "vous", 
       "2", "0", "d", "de", "sont", "«", "ou", "cette", "il", "B", "N", "x", "f", "", "s", "il", "i", "plus", 
       "Je", "r", "été", "se", "»", "p", "t", "O", "in", "d'une", "francs", "een", "", "rue", "ê", "op", "voor",
       "te", "", "", "", "qu'il", "tout", "", "ces", "conseil", "faire", "mais", "fait", "d'un", "U", "ont", "ii,", "ii",
       "c'est", "9", "h", "avec", "ville", "être", "budget", "publique", "g", "le", "comme", "collège", "art.", "aan", 
       "monsieur", "l'article", "on", "commission", "8", "j", "sera", "dat", "k", "soit", "bien", "", "die", "si", 
       "travaux", "f", "me", "communal", "d'assistance", "10", "décembre", "van", "m.", "+", "dont", "n°", "considérant", 
       "cela", "deux", "Les", "compte", "son", "dépense", "l'echevin", "loi", "crois", "n'est", "bruxelles", "Service", 
       "».", "%", "cours", "membres", "door", "er", "messieurs,", "messieurs", "met", "même", "is", "fr.", "fr", "très", "notre", "dit", 
       "worden", "mars", "leur", "question", "tôt", "donc", "avons", "der", "peut", "of", "tous", "entre", "rapport", 
       "encore", "service", "mesdames", "où", "ses", "plan", "", "sans", "cet", "non", "?", "*", "sa", "demande", "francs.", 
       "Nous", "ainsi", "faut", "dire", "part", "december", "La", "bourgmestre.", "bourgmestre" , "cas", "En", "bourgmestre,", "zijn", "", 
       "concerne", "vue", "sous", "vu", "2", "intervention,", "intervention", "aussi", "date", "parce", "nomination,", "nomination", "l'on", "taxe", "doit", 
       "niet", "prix", "l'etat", "juin", "lieu", "serait", "z", "personnel", "moins", "déjà", "", "partie", "nombre", "délibération", 
       "»,", "dépenses", "", "point", "avait", "wordt", "heer", "francs,", "c'est", "par", "14", "1967", "Bruxelles,", 
       "»,", "dépenses", "", "professeur", "voudrais", "", "J", "avis", "communes", "proposition", "frais", "janvier", "budget", 
       "également", "", "octobre", "", "deze", "depuis", "novembre", "que,", "recettes", "", "services", "bij", "rue", "het", 
       "a", "", "projet", "nos", "", "toutes", "toute", "trois", "mais"]
sw = set(sw)<jupyter_output><empty_output><jupyter_text>Vectoriser les documents à l'aide de TF-IDF en faisant passer la liste de stopwords<jupyter_code># Instancier le modèle TF-IDF avec ses arguments et on passe la liste de stop words
vectorizer2 = TfidfVectorizer(
    tokenizer=preprocessing,
    stop_words = sw,
    max_df=0.5,
    min_df=0.1,
    lowercase=True)

# Construire la matrice de vecteurs à l'aide de la fonction `fit_transform`
%time tfidf_vectors2 = vectorizer2.fit_transform(texts)

# Définir un nombre de clusters
N_CLUSTERS = 3

# Instancier le modèle K-Means et ses arguments
km_model2 = KMeans(n_clusters=N_CLUSTERS)

# Appliquer le clustering à l'aide de la fonction `fit_predict`
clusters2 = km_model2.fit_predict(tfidf_vectors2)

clustering2 = collections.defaultdict(list)

for idx, label in enumerate(clusters2):
    clustering2[label].append(files[idx])

pca2 = PCA(n_components=2)
reduced_vectors2 = pca2.fit_transform(tfidf_vectors2.toarray())

# Générer le plot
x_axis2 = reduced_vectors2[:, 0]
y_axis2 = reduced_vectors2[:, 1]

plt.figure(figsize=(10,10))
scatter2 = plt.scatter(x_axis2, y_axis2, s=100, c=clusters2)

# Ajouter les centroïdes
centroids2 = pca2.transform(km_model2.cluster_centers_)
plt.scatter(centroids2[:, 0], centroids2[:, 1],  marker = "x", s=100, linewidths = 2, color='black')

# Ajouter la légende
plt.legend(handles=scatter2.legend_elements()[0], labels=set(clusters2), title="Clusters")<jupyter_output>/usr/local/lib/python3.9/site-packages/sklearn/feature_extraction/text.py:396: UserWarning: Your stop_words may be inconsistent with your preprocessing. Tokenizing the stop words generated tokens ['art'] not in stop_words.
  warnings.warn(<jupyter_text>3. Analyse du  term frequency-inverse document frequency (TD-IDF)  Cluster 0<jupyter_code># Lister les fichiers du cluster 0 de notre première vectorisation

txts_0 = [f for f in clustering1[0] if os.path.isfile(os.path.join(txt_path, f))]
texts_0 = [open(data_path + f).read() for f in txts_0]

# Instancier le modèle TF-IDF avec ses arguments
vectorizer_0 = TfidfVectorizer(
    tokenizer=preprocessing,
    stop_words = stopwords.words("french"),
    max_df=0.5,
    min_df=0.1,
    lowercase=True)

# Construire la matrice de vecteurs à l'aide de la fonction `fit_transform`
tfidf_vectors_0 = vectorizer_0.fit_transform(texts_0)
pd.Series(
    tfidf_vectors_0[0].toarray()[0],
    index=vectorizer_0.get_feature_names_out()
    ).sort_values(ascending=False)
pd.Series(
    tfidf_vectors_0[1].toarray()[0],
    index=vectorizer_0.get_feature_names_out()
    ).sort_values(ascending=False)

pd.Series(
    tfidf_vectors_0[2].toarray()[0],
    index=vectorizer_0.get_feature_names_out()
    ).sort_values(ascending=False)

pd.Series(
    tfidf_vectors_0[3].toarray()[0],
    index=vectorizer_0.get_feature_names_out()
    ).sort_values(ascending=False)
pd.Series(
    tfidf_vectors_0[4].toarray()[0],
    index=vectorizer_0.get_feature_names_out()
    ).sort_values(ascending=False)
pd.Series(
    tfidf_vectors_0[5].toarray()[0],
    index=vectorizer_0.get_feature_names_out()
    ).sort_values(ascending=False)<jupyter_output><empty_output><jupyter_text>Cluster 1<jupyter_code># Lister les fichiers du cluster 1 de notre première vectorisation

txts_1 = [f for f in clustering1[1] if os.path.isfile(os.path.join(txt_path, f))]
texts_1 = [open(data_path + f).read() for f in txts_1]

# Instancier le modèle TF-IDF avec ses arguments
vectorizer_1 = TfidfVectorizer(
    tokenizer=preprocessing,
    stop_words = stopwords.words("french"),
    max_df=0.5,
    min_df=0.1,
    lowercase=True)

# Construire la matrice de vecteurs à l'aide de la fonction `fit_transform`
tfidf_vectors_1 = vectorizer_1.fit_transform(texts_1)

pd.Series(
    tfidf_vectors_1[0].toarray()[0],
    index=vectorizer_1.get_feature_names_out()
    ).sort_values(ascending=False)
pd.Series(
    tfidf_vectors_1[1].toarray()[0],
    index=vectorizer_1.get_feature_names_out()
    ).sort_values(ascending=False)

pd.Series(
    tfidf_vectors_1[2].toarray()[0],
    index=vectorizer_1.get_feature_names_out()
    ).sort_values(ascending=False)

pd.Series(
    tfidf_vectors_1[3].toarray()[0],
    index=vectorizer_1.get_feature_names_out()
    ).sort_values(ascending=False)
pd.Series(
    tfidf_vectors_1[4].toarray()[0],
    index=vectorizer_1.get_feature_names_out()
    ).sort_values(ascending=False)
pd.Series(
    tfidf_vectors_1[5].toarray()[0],
    index=vectorizer_1.get_feature_names_out()
    ).sort_values(ascending=False)<jupyter_output><empty_output><jupyter_text>Cluster 2<jupyter_code># Lister les fichiers du cluster 2 de notre première vectorisation

txts_2 = [f for f in clustering1[2] if os.path.isfile(os.path.join(txt_path, f))]
texts_2 = [open(data_path + f).read() for f in txts_2]

# Instancier le modèle TF-IDF avec ses arguments
vectorizer_2 = TfidfVectorizer(
    tokenizer=preprocessing,
    stop_words = stopwords.words("french"),
    max_df=0.5,
    min_df=0.1,
    lowercase=True)

# Construire la matrice de vecteurs à l'aide de la fonction `fit_transform`
tfidf_vectors_2 = vectorizer_2.fit_transform(texts_2)

pd.Series(
    tfidf_vectors_2[0].toarray()[0],
    index=vectorizer_2.get_feature_names_out()
    ).sort_values(ascending=False)
pd.Series(
    tfidf_vectors_2[1].toarray()[0],
    index=vectorizer_2.get_feature_names_out()
    ).sort_values(ascending=False)

pd.Series(
    tfidf_vectors_2[2].toarray()[0],
    index=vectorizer_2.get_feature_names_out()
    ).sort_values(ascending=False)

pd.Series(
    tfidf_vectors_2[3].toarray()[0],
    index=vectorizer_2.get_feature_names_out()
    ).sort_values(ascending=False)
pd.Series(
    tfidf_vectors_2[4].toarray()[0],
    index=vectorizer_2.get_feature_names_out()
    ).sort_values(ascending=False)
pd.Series(
    tfidf_vectors_2[5].toarray()[0],
    index=vectorizer_2.get_feature_names_out()
    ).sort_values(ascending=False)<jupyter_output><empty_output><jupyter_text>4.Word Embeddings : le modèle Word2Vec  Chargement et traitement des phrases du corpus<jupyter_code>class MySentences(object):
    """Tokenize and Lemmatize sentences"""
    def __init__(self, filename):
        self.filename = filename

    def __iter__(self):
        for line in open(self.filename, encoding='utf-8', errors="backslashreplace"):
            yield [unidecode(w.lower()) for w in wordpunct_tokenize(line)]
#en raison d'un processeur trop peu puissant, j'ai du limiter mon corpus à 1.500.000 lignes 
infile = f"../data/sents-1000000.txt"
sentences = MySentences(infile)<jupyter_output><empty_output><jupyter_text>Détection des bigrams<jupyter_code>bigram_phrases = Phrases(sentences)
%time bigram_phrases[sentences]
bigram_phraser = Phraser(phrases_model=bigram_phrases)
%time bigram_phraser[sentences]<jupyter_output>CPU times: user 5.51 ms, sys: 79 µs, total: 5.59 ms
Wall time: 11.6 ms<jupyter_text>Extraction des trigrams<jupyter_code>trigram_phrases = Phrases(bigram_phraser[sentences])
trigram_phraser = Phraser(phrases_model=trigram_phrases)<jupyter_output><empty_output><jupyter_text>Création d'un corpus d'unigrams, bigrams, trigrams<jupyter_code>corpus = list(trigram_phraser[bigram_phraser[sentences]])<jupyter_output><empty_output><jupyter_text>Entrainement d'un modèle Word2Vec sur ce corpus<jupyter_code># window de 10 et minimum count de 3
model_10 = Word2Vec(
    corpus, # On passe le corpus de ngrams que nous venons de créer
    vector_size=32, # Le nombre de dimensions dans lesquelles le contexte des mots devra être réduit, aka. vector_size
    window=10, # La taille du "contexte", ici 10 mots avant et après le mot observé
    min_count=3, # On ignore les mots qui n'apparaissent pas au moins 3 fois dans le corpus
    workers=4, # Permet de paralléliser l'entraînement du modèle en 4 threads
    epochs=5 # Nombre d'itérations du réseau de neurones sur le jeu de données pour ajuster les paramètres avec la descende de gradient, aka. epochs.
)
# window de 5 et minimum count de 3
model_5 = Word2Vec(
    corpus, # On passe le corpus de ngrams que nous venons de créer
    vector_size=32, # Le nombre de dimensions dans lesquelles le contexte des mots devra être réduit, aka. vector_size
    window=5, # La taille du "contexte", ici 5 mots avant et après le mot observé
    min_count=3, # On ignore les mots qui n'apparaissent pas au moins 3 fois dans le corpus
    workers=4, # Permet de paralléliser l'entraînement du modèle en 4 threads
    epochs=5 # Nombre d'itérations du réseau de neurones sur le jeu de données pour ajuster les paramètres avec la descende de gradient, aka. epochs.
)
# window de 5 et minimum count de 3
model_3 = Word2Vec(
    corpus, # On passe le corpus de ngrams que nous venons de créer
    vector_size=32, # Le nombre de dimensions dans lesquelles le contexte des mots devra être réduit, aka. vector_size
    window=3, # La taille du "contexte", ici 3 mots avant et après le mot observé
    min_count=3, # On ignore les mots qui n'apparaissent pas au moins 3 fois dans le corpus
    workers=4, # Permet de paralléliser l'entraînement du modèle en 4 threads
    epochs=5 # Nombre d'itérations du réseau de neurones sur le jeu de données pour ajuster les paramètres avec la descende de gradient, aka. epochs.
)
outfile_10 = f"../data/bulletins_10.model"
model_10.save(outfile_10)
outfile_5 = f"../data/bulletins_5.model"
model_5.save(outfile_5)
outfile_3 = f"../data/bulletins_3.model"
model_3.save(outfile_3)
# Charger les modèles en mémoire
model_10 = Word2Vec.load("../data/bulletins_10.model")
model_5 = Word2Vec.load("../data/bulletins_5.model")
model_3 = Word2Vec.load("../data/bulletins_3.model")<jupyter_output><empty_output><jupyter_text>Calculer la similarité entre deux termes<jupyter_code># modèle avec une fenêtre de 10
model_10.wv.similarity("pyck", "boulangerie")
# modèle avec une fenêtre de 5
model_5.wv.similarity("pyck", "boulangerie")
# modèle avec une fenêtre de 3
model_3.wv.similarity("pyck", "boulangerie")
# modèle avec une fenêtre de 10
model_10.wv.similarity("hospices", "secours")
# modèle avec une fenêtre de 5
model_5.wv.similarity("hospices", "secours")
# modèle avec une fenêtre de 3
model_3.wv.similarity("hospices", "secours")
# modèle avec une fenêtre de 10
model_10.wv.similarity("senne", "eau")
# modèle avec une fenêtre de 5
model_5.wv.similarity("senne", "eau")
# modèle avec une fenêtre de 3
model_3.wv.similarity("senne", "eau")<jupyter_output><empty_output><jupyter_text>Chercher les mots les plus proches d'un terme donné<jupyter_code># Pyck avec le modèle 10
model_10.wv.most_similar("pyck", topn=10)
# Pyck avec le modèle 5
model_5.wv.most_similar("pyck", topn=10)
# Pyck avec le modèle 3
model_3.wv.most_similar("pyck", topn=10)
# hospices avec le modèle 10
model_10.wv.most_similar("hospices", topn=10)
# hospices avec le modèle 5
model_5.wv.most_similar("hospices", topn=10)
# hospices avec le modèle 3
model_3.wv.most_similar("hospices", topn=10)
# Senne avec le modèle 10
model_10.wv.most_similar("senne", topn=10)
# Senne avec le modèle 5
model_5.wv.most_similar("senne", topn=10)
# Senne avec le modèle 3
model_3.wv.most_similar("senne", topn=10)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1447874265038444, 'fraction_numerical': 0.024762550881953865, 'mean_word_length': 5.268249468462083, 'pattern_counts': {'":': 1, '<': 65, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '17', 'dir': 'jupyter-structured-clean-dedup', 'id': '288964', 'license': 'MIT', 'n_tokens_mistral': 7013, 'n_tokens_neox': 6761, 'n_words': 1622, 'path': 'TP3/TP3.ipynb', 'repo_name': 'gitmava2311/tac', 'size': '17688'}