181 lines
No EOL
6.9 KiB
Python
Executable file
181 lines
No EOL
6.9 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
Script pour analyser la fréquence des mots dans un fichier livre.org
|
|
et générer un nuage de mots coloré en tons pastels.
|
|
|
|
Ce script:
|
|
1. Lit le fichier livre.org
|
|
2. Extrait le texte en ignorant les métadonnées et les commentaires
|
|
3. Compte la fréquence des mots
|
|
4. Sauvegarde les 500 mots les plus fréquents dans un fichier CSV
|
|
5. Génère un nuage de mots en SVG et PNG avec des couleurs pastel aléatoires
|
|
"""
|
|
|
|
import re
|
|
import os
|
|
import csv
|
|
import random
|
|
import argparse
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
from collections import Counter
|
|
from wordcloud import WordCloud
|
|
import matplotlib.colors as mcolors
|
|
|
|
# Définir les arguments en ligne de commande
|
|
parser = argparse.ArgumentParser(description='Analyser la fréquence des mots dans un fichier Org-mode.')
|
|
parser.add_argument('dossier', nargs='?', help='Le chemin du dossier contenant le fichier livre.org. Si aucun dossier n\'est spécifié, le dossier courant sera utilisé.', default=os.getcwd())
|
|
args = parser.parse_args()
|
|
|
|
# Chemin vers le fichier livre.org
|
|
fichier_livre = f"{args.dossier}/livre.org"
|
|
|
|
# Liste des mots vides (stopwords) en français
|
|
stopwords = set([
|
|
"le", "la", "les", "un", "une", "des", "du", "de", "d'", "l'", "et", "ou", "où",
|
|
"à", "au", "aux", "ce", "ces", "cette", "cet", "il", "ils", "elle", "elles",
|
|
"nous", "vous", "je", "tu", "on", "son", "sa", "ses", "leur", "leurs", "mon",
|
|
"ma", "mes", "ton", "ta", "tes", "que", "qui", "quoi", "dont", "pour", "par",
|
|
"dans", "sur", "sous", "avec", "sans", "en", "y", "est", "sont", "était",
|
|
"étaient", "sera", "seront", "a", "ont", "avait", "avaient", "aura", "auront",
|
|
"plus", "moins", "très", "peu", "beaucoup", "trop", "pas", "ne", "n'", "si",
|
|
"comme", "mais", "ou", "et", "donc", "car", "quand", "lorsque", "puis", "ensuite",
|
|
"alors", "ainsi", "aussi", "même", "tout", "tous", "toute", "toutes", "autre",
|
|
"autres", "certain", "certains", "certaine", "certaines", "tel", "tels", "telle",
|
|
"telles", "ceci", "cela", "ça", "c'", "s'", "d'", "l'", "qu'", "n'", "m'", "t'",
|
|
"se", "me", "te", "lui", "leur", "y", "en", "là", "ici", "voici", "voilà", "ci",
|
|
"là", "cet", "cette", "ces", "celui", "celle", "ceux", "celles", "celui-ci",
|
|
"celle-ci", "ceux-ci", "celles-ci", "celui-là", "celle-là", "ceux-là", "celles-là"
|
|
])
|
|
|
|
def generate_pastel_color():
|
|
"""Génère une couleur pastel aléatoire en format RGB."""
|
|
# NOTE: PIL's ImageDraw requires integer RGB values (0-255), not floats.
|
|
# La version précédente retournait des valeurs flottantes entre 0.6 et 0.9,
|
|
# ce qui causait une erreur: 'float' object cannot be interpreted as an integer
|
|
|
|
# Générer des valeurs RGB entre 153 et 229 (0.6*255 et 0.9*255) pour obtenir des tons pastels
|
|
# tout en convertissant en entiers pour la compatibilité avec PIL
|
|
r = int(random.uniform(0.6, 0.9) * 255)
|
|
g = int(random.uniform(0.6, 0.9) * 255)
|
|
b = int(random.uniform(0.6, 0.9) * 255)
|
|
return (r, g, b)
|
|
|
|
def extract_text_from_org(file_path):
|
|
"""
|
|
Extrait le texte d'un fichier org-mode en ignorant les métadonnées et les commentaires.
|
|
"""
|
|
with open(file_path, 'r', encoding='utf-8') as file:
|
|
content = file.read()
|
|
|
|
# Supprimer les blocs de commentaires
|
|
content = re.sub(r'#\+begin_comment.*?#\+end_comment', '', content, flags=re.DOTALL | re.IGNORECASE)
|
|
|
|
# Supprimer les lignes de métadonnées (commençant par #+)
|
|
content = re.sub(r'^\s*#\+.*$', '', content, flags=re.MULTILINE)
|
|
|
|
# Supprimer les lignes de propriétés
|
|
content = re.sub(r'^\s*:.*:.*$', '', content, flags=re.MULTILINE)
|
|
|
|
# Supprimer les titres de chapitres (lignes commençant par * ou **)
|
|
content = re.sub(r'^\s*\*+.*$', '', content, flags=re.MULTILINE)
|
|
|
|
# Supprimer les liens org-mode [[...][...]] et [[...]]
|
|
content = re.sub(r'\[\[.*?\]\](?:\[.*?\])?', '', content)
|
|
|
|
# Supprimer les caractères spéciaux et la ponctuation
|
|
content = re.sub(r'[^\w\s]', ' ', content)
|
|
|
|
# Convertir en minuscules
|
|
content = content.lower()
|
|
|
|
return content
|
|
|
|
def count_word_frequencies(text):
|
|
"""
|
|
Compte la fréquence des mots dans un texte.
|
|
Ignore les mots vides (stopwords) et les mots de moins de 3 caractères.
|
|
"""
|
|
# Diviser le texte en mots
|
|
words = re.findall(r'\b\w+\b', text)
|
|
|
|
# Filtrer les mots courts et les stopwords
|
|
filtered_words = [word for word in words if len(word) >= 3 and word not in stopwords]
|
|
|
|
# Compter les fréquences
|
|
word_counts = Counter(filtered_words)
|
|
|
|
return word_counts
|
|
|
|
def save_to_csv(word_counts, output_path, limit=500):
|
|
"""
|
|
Sauvegarde les mots les plus fréquents dans un fichier CSV.
|
|
"""
|
|
# Obtenir les mots les plus fréquents
|
|
most_common = word_counts.most_common(limit)
|
|
|
|
# Écrire dans le fichier CSV
|
|
with open(output_path, 'w', newline='', encoding='utf-8') as csvfile:
|
|
writer = csv.writer(csvfile)
|
|
writer.writerow(['Mot', 'Fréquence'])
|
|
for word, count in most_common:
|
|
writer.writerow([word, count])
|
|
|
|
print(f"Les {limit} mots les plus fréquents ont été sauvegardés dans {output_path}")
|
|
|
|
def generate_wordcloud(word_counts, output_svg, output_png):
|
|
"""
|
|
Génère un nuage de mots en SVG et PNG avec des couleurs pastel aléatoires.
|
|
"""
|
|
# Fonction pour attribuer des couleurs pastel aléatoires aux mots
|
|
def color_func(word, font_size, position, orientation, random_state=None, **kwargs):
|
|
return generate_pastel_color()
|
|
|
|
# Créer le nuage de mots
|
|
wordcloud = WordCloud(
|
|
width=1200,
|
|
height=800,
|
|
background_color='white',
|
|
max_words=500,
|
|
color_func=color_func,
|
|
prefer_horizontal=0.9,
|
|
relative_scaling=0.5
|
|
).generate_from_frequencies(word_counts)
|
|
|
|
# Sauvegarder en SVG
|
|
plt.figure(figsize=(12, 8), dpi=300)
|
|
plt.imshow(wordcloud, interpolation='bilinear')
|
|
plt.axis('off')
|
|
plt.tight_layout(pad=0)
|
|
plt.savefig(output_svg, format='svg', bbox_inches='tight')
|
|
|
|
# Sauvegarder en PNG
|
|
plt.savefig(output_png, format='png', bbox_inches='tight')
|
|
|
|
plt.close()
|
|
|
|
print(f"Nuage de mots sauvegardé en SVG: {output_svg}")
|
|
print(f"Nuage de mots sauvegardé en PNG: {output_png}")
|
|
|
|
def main():
|
|
# Extraire le texte du fichier livre.org
|
|
print(f"Analyse du fichier: {fichier_livre}")
|
|
text = extract_text_from_org(fichier_livre)
|
|
|
|
# Compter les fréquences des mots
|
|
word_counts = count_word_frequencies(text)
|
|
|
|
# Définir les chemins de sortie
|
|
csv_output = f"{args.dossier}/frequence_mots_top500.csv"
|
|
svg_output = f"{args.dossier}/nuage_mots.svg"
|
|
png_output = f"{args.dossier}/nuage_mots.png"
|
|
|
|
# Sauvegarder les résultats
|
|
save_to_csv(word_counts, csv_output)
|
|
generate_wordcloud(word_counts, svg_output, png_output)
|
|
|
|
print("Analyse de fréquence des mots terminée avec succès!")
|
|
|
|
if __name__ == "__main__":
|
|
main() |