Analisi email spam
Versione integrata nel sito senza iframe. Il notebook ricostruito resta disponibile come file .ipynb.
Codice
Gabriele Iocco
Analisi e Classificazione delle Email per la Rilevazione di SPAM
Integrazione e controllo dell'hardware CUDA per Machine Learning
Gestione della Memoria GPU e Allocazioni Dinamiche
Codice
import warnings
warnings.filterwarnings("ignore")
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='1'
import tensorflow as tf
tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
gpu_devices = tf.config.list_physical_devices('GPU')
if gpu_devices:
try:
for gpu in gpu_devices:
tf.config.experimental.set_memory_growth(gpu, True)
except RuntimeError as e:
print(e)
print("Dispositivi GPU rilevati:", gpu_devices)
import torch
print(f"CUDA available: {torch.cuda.is_available()}")
print(f"CUDA device count: {torch.cuda.device_count()}")
print(f"CUDA device name: {torch.cuda.get_device_name(0)}" if torch.cuda.is_available() else "No CUDA device found")
print("Dispositivo corrente:", torch.cuda.current_device() if torch.cuda.is_available() else "CPU")
print("TensorFlow version:", tf.__version__)
print("CUDA disponibile:", tf.config.list_physical_devices('GPU'))
print("cuDNN Version:", tf.sysconfig.get_build_info()['cudnn_version'])
print("CUDA Version:", tf.sysconfig.get_build_info()["cuda_version"])
print("Test CUDA:", tf.test.is_built_with_cuda())
print("GPU available:", tf.test.is_gpu_available())
Dispositivi GPU rilevati: [PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')] CUDA available: True CUDA device count: 1 CUDA device name: NVIDIA GeForce RTX 4070 Laptop GPU Dispositivo corrente: 0 TensorFlow version: 2.18.0 CUDA disponibile: [PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')] cuDNN Version: 9 CUDA Version: 12.5.1 Test CUDA: True GPU available: True
I0000 00:00:1737558820.769880 19448 gpu_device.cc:2022] Created device /device:GPU:0 with 5472 MB memory: -> device: 0, name: NVIDIA GeForce RTX 4070 Laptop GPU, pci bus id: 0000:01:00.0, compute capability: 8.9
Codice
# Configurazioni GPU TensorFlow
os.environ['TF_FORCE_GPU_ALLOW_GROWTH'] = 'true'
os.environ['XLA_FLAGS'] = '--xla_gpu_cuda_data_dir=/usr/lib/cuda'
os.environ['TF_GPU_ALLOCATOR'] = 'cuda_malloc_async'
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
# Configurazione della memoria GPU
gpus = tf.config.list_physical_devices('GPU')
if gpus:
for gpu in gpus:
try:
tf.config.experimental.set_memory_growth(gpu, True)
except RuntimeError as e:
print(e)
Codice
os.environ['TF_FORCE_GPU_ALLOW_GROWTH'] = 'true'
os.environ['XLA_FLAGS'] = '--xla_gpu_cuda_data_dir=/usr/lib/cuda'
Codice
import cupy as cp
print("CuPy version:", cp.__version__)
CuPy version: 13.3.0
Codice
from thinc.api import require_gpu, set_gpu_allocator
import spacy
require_gpu() # Forza l'uso della GPU
nlp = spacy.load("en_core_web_trf")
print("Preferenza GPU da SpaCy:", spacy.prefer_gpu())
Preferenza GPU da SpaCy: True
Analisi del dataset
Codice
from colorama import Fore, Back, Style
from tensorflow.keras.backend import clear_session
import pandas as pd
import matplotlib.pyplot as plt
Codice
# Funzione personalizzata per colorare il testo
def print_colored(text, color="white", bg_color=None, end="\n"):
# Dizionario dei colori del testo
color_dict = {
'red': Fore.RED,
'blue': Fore.BLUE,
'white': '\033[97m', # Bianco puro (ANSI)
'black': Fore.BLACK
}
# Dizionario dei colori dello sfondo
bg_color_dict = {
'black': Back.BLACK,
'blue': Back.BLUE,
'white': Back.WHITE
}
color_code = color_dict.get(color.lower(), '\033[97m')
bg_color_code = bg_color_dict.get(bg_color.lower(), '') if bg_color else ''
print(f"{color_code}{bg_color_code}{text}{Style.RESET_ALL}", end=end)
Codice
BASE_URL="/home/gap/Scrivania/Analisi_spam/"
Codice
df_email = pd.read_csv(BASE_URL + "spam_dataset.csv")
Codice
# Calcolo del peso totale del dataset in memoria
dataset_size_ham_spam = df_email.memory_usage(deep=True).sum()
# Conversione in megabyte (MB)
dataset_size_ham_spam_mb = dataset_size_ham_spam / (1024 ** 2)
print_colored(f"Il peso del dataset in memoria è di:", "blue")
print(f"{dataset_size_ham_spam_mb:.2f} MB")
Il peso del dataset in memoria è di:
5.66 MB
Codice
df_email.head()
Out[12]:
| Unnamed: 0 | label | text | label_num | |
|---|---|---|---|---|
| 0 | 605 | ham | Subject: enron methanol ; meter # : 988291\nth... | 0 |
| 1 | 2349 | ham | Subject: hpl nom for january 9 , 2001\n( see a... | 0 |
| 2 | 3624 | ham | Subject: neon retreat\nho ho ho , we ' re arou... | 0 |
| 3 | 4685 | spam | Subject: photoshop , windows , office . cheap ... | 1 |
| 4 | 2030 | ham | Subject: re : indian springs\nthis deal is to ... | 0 |
Codice
df_email.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 5171 entries, 0 to 5170 Data columns (total 4 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Unnamed: 0 5171 non-null int64 1 label 5171 non-null object 2 text 5171 non-null object 3 label_num 5171 non-null int64 dtypes: int64(2), object(2) memory usage: 161.7+ KB
Codice
print_colored("Numero di righe:", "blue")
print(df_email.shape[0])
print()
print_colored("Numero di colonne:", "blue")
print(df_email.shape[1])
Numero di righe: 5171 Numero di colonne: 4
Codice
df_email.count()
Out[15]:
Unnamed: 0 5171 label 5171 text 5171 label_num 5171 dtype: int64
Codice
total_values = df_email.size
print_colored("Valori totali presenti nel dataset:", "blue")
print(total_values)
non_missing_values = df_email.count().sum()
print_colored("Valori totali 'non_missing' presenti nel dataset:", "blue")
print(non_missing_values)
missing_values = total_values - non_missing_values
print_colored("\nValori mancanti", "blue")
print(missing_values)
Valori totali presenti nel dataset: 20684 Valori totali 'non_missing' presenti nel dataset: 20684 Valori mancanti 0
Codice
print_colored("Valori mancanti per colonna:\n", "blue")
print(df_email.isna())
Valori mancanti per colonna:
Unnamed: 0 label text label_num
0 False False False False
1 False False False False
2 False False False False
3 False False False False
4 False False False False
... ... ... ... ...
5166 False False False False
5167 False False False False
5168 False False False False
5169 False False False False
5170 False False False False
[5171 rows x 4 columns]
Codice
print_colored("Valori mancanti per colonna:\n", "blue")
print(df_email.isnull())
Valori mancanti per colonna:
Unnamed: 0 label text label_num
0 False False False False
1 False False False False
2 False False False False
3 False False False False
4 False False False False
... ... ... ... ...
5166 False False False False
5167 False False False False
5168 False False False False
5169 False False False False
5170 False False False False
[5171 rows x 4 columns]
Codice
df_email.describe()
Out[19]:
| Unnamed: 0 | label_num | |
|---|---|---|
| count | 5171.000000 | 5171.000000 |
| mean | 2585.000000 | 0.289886 |
| std | 1492.883452 | 0.453753 |
| min | 0.000000 | 0.000000 |
| 25% | 1292.500000 | 0.000000 |
| 50% | 2585.000000 | 0.000000 |
| 75% | 3877.500000 | 1.000000 |
| max | 5170.000000 | 1.000000 |
Codice
# Controllo di possibili incongruenze tra label e label_num
# La variabile inconsistencies viene popolata con le righe che non
# rispettano le corrispondenze attese
inconsistencies = df_email[
((df_email['label'] == 'ham') & (df_email['label_num'] != 0)) |
((df_email['label'] == 'spam') & (df_email['label_num'] != 1))
]
if inconsistencies.empty:
print_colored("Tutte le righe corrispondono correttamente", "blue")
print ("ham -> 0, spam -> 1")
else:
print_colored(f"Ci sono {len(inconsistencies)} righe con incongruenze:", "blue")
print(inconsistencies)
Tutte le righe corrispondono correttamente
ham -> 0, spam -> 1
Visto che c'è una perfetta corrispondenza tra le feature "label" e "label_num", faccio il drop della colonna "label", anche perché, se scegliessi la feature categorica, dovrei applicare la tecnica del Label Encoding per convertire le variabili categoriali in formato numerico.
Faccio il drop anche della colonna "Unnamed:0".
La colonna Unnamed:0 appare frequentemente quando si caricano file CSV in un DataFrame di pandas.
Codice
df_email_dropped = df_email.drop(columns=['Unnamed: 0', 'label'])
print_colored("Dataset dropped\n", "blue")
print(df_email_dropped.head())
Dataset dropped
text label_num
0 Subject: enron methanol ; meter # : 988291\nth... 0
1 Subject: hpl nom for january 9 , 2001\n( see a... 0
2 Subject: neon retreat\nho ho ho , we ' re arou... 0
3 Subject: photoshop , windows , office . cheap ... 1
4 Subject: re : indian springs\nthis deal is to ... 0
Verifico la distribuzione di ham e spam nel dataset droppato
Codice
label_count=df_email_dropped[df_email_dropped.columns[1]].value_counts()
Codice
print_colored("Distribuzione di ham e spam\n", "blue")
print(label_count)
Distribuzione di ham e spam
label_num
0 3672
1 1499
Name: count, dtype: int64
Codice
label_count.plot(kind='bar', figsize=(10, 6))
plt.title("\nDistribuzione di ham e spam", fontsize=18)
plt.xlabel("Label (0 = ham, 1 = spam)", fontsize=14)
plt.ylabel("Conteggio", fontsize=14)
plt.xticks(fontsize=12, color='#b81414', rotation=0)
plt.yticks(fontsize=12, color='#b81414')
plt.grid(axis='y', linestyle='--', alpha=0.5, color="#1f77b4")
plt.show()
Codice
# Calcolo della differenza in percentuale
total_label = label_count.sum()
difference_percentage = ((label_count.max() - label_count.min()) / total_label) * 100
print_colored(f"La differenza in percentuale tra ham e spam è del:", "blue")
print(f"{difference_percentage:.2f}%")
La differenza in percentuale tra ham e spam è del:
42.02%
Preprocessing del Testo delle email SPAM
Codice
import re
import nltk
import nltk.corpus
from nltk.corpus import stopwords
from nltk.stem import WordNetLemmatizer
from nltk import download
download('stopwords')
download('wordnet')
download('omw-1.4')
[nltk_data] Downloading package stopwords to /home/gap/nltk_data... [nltk_data] Package stopwords is already up-to-date! [nltk_data] Downloading package wordnet to /home/gap/nltk_data... [nltk_data] Package wordnet is already up-to-date! [nltk_data] Downloading package omw-1.4 to /home/gap/nltk_data... [nltk_data] Package omw-1.4 is already up-to-date!
Out[26]:
True
Codice
# Inizializzazione di stopwords e lemmatizer
stop_words = set(stopwords.words('english')) # Stopword per la lingua inglese
# Rimuove parole comuni inglesi per ridurre il rumore nei dati
lemmatizer = WordNetLemmatizer() # Riduce le parole alla loro forma base per
# diminuire la dimensionalità del vocabolario
def clean_text(text):
# Rimozione di caratteri speciali e punteggiatura
text = re.sub(r'[^a-zA-Z\s]', '', text)
# Conversione di tutte le lettere in minuscolo
text = text.lower()
# Rimozione della parola 'subject' se presente perché si riferisce alla struttura standard di un'email
# non aggiunge valore informativo per l'analisi, anzi, può influenzarla negativamente
text = text.replace('subject', '')
tokens = [lemmatizer.lemmatize(word, pos='v') for word in text.split() if word not in stop_words]
return ' '.join(tokens)
# Filtro le email SPAM e creo una copia per evitare SettingWithCopyWarning
# Il warning SettingWithCopyWarning si verifica quando si modificano direttamente valori di un DataFrame filtrato
df_email_dropped_spam = df_email_dropped[df_email_dropped['label_num'] == 1].copy()
# Creazione della colonna cleaned_text con i dati della colonna text puliti
df_email_dropped_spam['cleaned_text'] = df_email_dropped_spam['text'].apply(clean_text)
print_colored("Dataset 'df_email_dropped_spam' senza l'applicazione della funzione 'clean_text' alla colonna 'text'", "blue")
print(df_email_dropped_spam[['text']].head())
print()
print_colored("Dataset 'df_email_dropped_spam' con l'applicazione della funzione 'clean_text' alla colonna 'text'", "blue")
print(df_email_dropped_spam[['cleaned_text']].head())
Dataset 'df_email_dropped_spam' senza l'applicazione della funzione 'clean_text' alla colonna 'text' text 3 Subject: photoshop , windows , office . cheap ... 7 Subject: looking for medication ? we ` re the ... 10 Subject: vocable % rnd - word asceticism\nvcsc... 11 Subject: report 01405 !\nwffur attion brom est... 13 Subject: vic . odin n ^ ow\nberne hotbox carna... Dataset 'df_email_dropped_spam' con l'applicazione della funzione 'clean_text' alla colonna 'text' cleaned_text 3 photoshop windows office cheap main trend abas... 7 look medication best source difficult make mat... 10 vocable rnd word asceticism vcsc brand new sto... 11 report wffur attion brom est inst siupied pgst... 13 vic odin n ow berne hotbox carnal bride cutwor...
Codice
print(df_email_dropped_spam.head())
text label_num \
3 Subject: photoshop , windows , office . cheap ... 1
7 Subject: looking for medication ? we ` re the ... 1
10 Subject: vocable % rnd - word asceticism\nvcsc... 1
11 Subject: report 01405 !\nwffur attion brom est... 1
13 Subject: vic . odin n ^ ow\nberne hotbox carna... 1
cleaned_text
3 photoshop windows office cheap main trend abas...
7 look medication best source difficult make mat...
10 vocable rnd word asceticism vcsc brand new sto...
11 report wffur attion brom est inst siupied pgst...
13 vic odin n ow berne hotbox carnal bride cutwor...
Codice
# Verifico se il conteggio dei valori della colonna 'label num' riferito
# alle mail spam sia uguale al conteggio di partenza
df_email_dropped_spam[df_email_dropped_spam.columns[1]].value_counts()
Out[29]:
label_num 1 1499 Name: count, dtype: int64
Codice
# Calcolo del peso totale del dataset contenente solo SPAM droppato e pulito in memoria
dataset_size_dropped_spam = df_email_dropped_spam[['cleaned_text', 'label_num']].memory_usage(deep=True).sum()
# Conversione in megabyte (MB)
dataset_size_mb_dropped = dataset_size_dropped_spam / (1024 ** 2)
print_colored(f"Il peso del dataset droppato, pulito e contenente solo spam in memoria è di:", "blue")
print(f"{dataset_size_mb_dropped:.2f} MB")
Il peso del dataset droppato, pulito e contenente solo spam in memoria è di:
1.28 MB
Codice
dataset_size_difference = dataset_size_ham_spam_mb - dataset_size_mb_dropped
print_colored(f"La memoria liberata grazie al dropout e alla pulizia del testo è di:", "blue")
print(f"{dataset_size_difference:.2f} MB")
total_size = dataset_size_ham_spam_mb + dataset_size_mb_dropped
difference_percentage_size = (dataset_size_difference/total_size)*100
print_colored(f"Percentuale di memoria liberata:", "blue")
print(f"{difference_percentage_size:.2f} %")
La memoria liberata grazie al dropout e alla pulizia del testo è di: 4.38 MB Percentuale di memoria liberata: 63.10 %
Codice
# Calcolo del numero totale di parole nella colonna 'cleaned_text'
total_word_count = df_email_dropped_spam['cleaned_text'].str.split().str.len().sum()
print_colored(f"Il numero totale di parole nella colonna 'cleaned_text' è di:", "blue")
print(f"{total_word_count}")
Il numero totale di parole nella colonna 'cleaned_text' è di:
177805
Implementazione Multi-Modello
Costruzione e addestramento di modelli Word2Vec per l'analisi delle email classificate come SPAM
Utilizzerò la tecnica Word2Vec per rappresentare le parole come vettori densi, ovvero rappresentazioni numeriche compatte che collocano i dati nello spazio semantico. Questo metodo consente di ottenere embedding capaci di catturare le relazioni semantiche tra le parole, posizionandole in uno spazio vettoriale in cui parole dal significato simile risultano vicine tra loro. Successivamente, applicherò l'algoritmo K-Means per il clustering, al fine di identificare gruppi semantici significativi generati dal modello. Questo approccio risulta particolarmente efficace in contesti caratterizzati da dati rumorosi o ad alta dimensionalità semantica.
Gli obiettivi di questi modelli saranno:
- Individuare i Topic principali tra le email classificate come SPAM.
- Calcolare la distanza semantica tra i topic ottenuti per valutare l'eterogeneità dei contenuti delle email SPAM.
- Analisi contenutistica approfondita individuando i principali topic trattati nelle email SPAM consentendo di ottenere informazioni preziose sui trend, tematiche e schemi ricorrenti, potenziando le strategie di cybersecurity.
- Valutazione dell'eterogeneità calcolando la distanza semantica tra i topic e quindi comprendere la diversità dei contenuti SPAM, utile per ottimizzare le difese contro un'ampia gamma di attacchi.
Codice
from gensim.models import Word2Vec
from gensim.models import CoherenceModel
from gensim.corpora.dictionary import Dictionary
from sklearn.metrics import silhouette_score
from sklearn.cluster import KMeans
import multiprocessing
# Tokenizzazione
# divide il testo in token (parole e sottoparole) e assegna un identificatore numerico univoco a ogni token
tokenized_texts = [text.split() for text in df_email_dropped_spam['cleaned_text']]
# Creazione del dizionario per Coherence Score
dictionary = Dictionary(tokenized_texts)
# Configurazioni da testare
configs = [
{"name": "model_vec50_win3", "vector_size": 50, "window": 3, "min_count": 2, "sg": 1},
{"name": "model_vec100_win3", "vector_size": 100, "window": 3, "min_count": 2, "sg": 1},
{"name": "model_vec100_win5", "vector_size": 100, "window": 5, "min_count": 2, "sg": 1},
{"name": "model_vec200_win3", "vector_size": 200, "window": 3, "min_count": 2, "sg": 1},
{"name": "model_vec200_win5", "vector_size": 200, "window": 5, "min_count": 2, "sg": 1},
]
# Funzione per estrarre i topic da Word2Vec
def extract_topics_from_word2vec(model, n_topics, topn=10):
word_vectors = np.array([model.wv[word] for word in model.wv.index_to_key])
words = model.wv.index_to_key
# Clustering con KMeans
kmeans = KMeans(n_clusters=n_topics, random_state=42)
labels = kmeans.fit_predict(word_vectors)
# Raggruppamento delle parole per cluster
topics = []
for cluster in range(n_topics):
words_in_cluster = [words[i] for i, label in enumerate(labels) if label == cluster]
topics.append(words_in_cluster[:topn])
return topics
# Per salvare i risultati
results_main = []
# Numero di topic da testare
n_topics_list = [2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20]
# Addestramento e valutazione dei modelli
for config in configs:
print_colored(f"Addestramento del modello: {config['name']}", "blue")
# Addestramento del modello Word2Vec
"""
vector_size indica la dimensione del vettore generato per ogni parola
window indica la dimensione del contesto, il numero di parole vicine considerate per ogni parola
Siccome il progetto prevede un'analisi contenutistica approfondita lo imposto a 3 e 5
min_count, le parole con una frequenza inferiore a questo valore vengono ignorate
sg Skip-gram indica il tipo di architettura
Skip-gram cattura relazioni semantiche
"""
# Embedding delle parole
# converte i token in vettori densi, cattura relazioni semantiche tra token
# rappresenta il significato contestuale dei token
model = Word2Vec(
sentences=tokenized_texts,
vector_size=config["vector_size"],
window=config["window"],
min_count=config["min_count"],
workers=multiprocessing.cpu_count(),
sg=config["sg"]
)
model.save(f"{config['name']}.model")
for n_topics in n_topics_list:
try:
# Estrazione dei topic
topics = extract_topics_from_word2vec(model, n_topics)
# Calcolo del Coherence Score
coherence_model = CoherenceModel(
topics=topics,
texts=tokenized_texts,
dictionary=dictionary,
coherence="c_v"
)
coherence_score = coherence_model.get_coherence()
# Calcolo del Silhouette Score
word_vectors = np.array([model.wv[word] for word in model.wv.index_to_key])
silhouette_avg = silhouette_score(word_vectors, KMeans(n_clusters=n_topics, random_state=42).fit_predict(word_vectors))
# Salvataggio dei risultati
results_main.append({
"model_name": config["name"],
"vector_size": config["vector_size"],
"window": config["window"],
"n_topics": n_topics,
"coherence_c_v": coherence_score,
"silhouette": silhouette_avg,
})
except Exception as e:
print(f"Errore per {config['name']} con {n_topics} topic: {e}")
results_main.append({
"model_name": config["name"],
"vector_size": config["vector_size"],
"window": config["window"],
"n_topics": n_topics,
"coherence_c_v": None,
"silhouette": None,
})
# Conversione in DataFrame per analisi
results_df_main = pd.DataFrame(results_main)
Addestramento del modello: model_vec50_win3 Addestramento del modello: model_vec100_win3 Addestramento del modello: model_vec100_win5 Addestramento del modello: model_vec200_win3 Addestramento del modello: model_vec200_win5
Codice
print_colored(f"Modelli costruiti e addestrati:", "blue")
for config in configs:
print(config['name'])
Modelli costruiti e addestrati:
model_vec50_win3
model_vec100_win3
model_vec100_win5
model_vec200_win3
model_vec200_win5
Codice
print_colored("Colonne disponibili:", "blue")
print(results_df_main.columns)
Colonne disponibili:
Index(['model_name', 'vector_size', 'window', 'n_topics', 'coherence_c_v',
'silhouette'],
dtype='object')
Codice
from tabulate import tabulate
# Raggruppamento per modello e numero di topic
table = results_df_main.pivot(
index="n_topics",
columns="model_name",
values="coherence_c_v"
)
# Riordino le colonne per chiarezza
table = table[sorted(table.columns)]
# Evidenziazione dei valori più alti in ogni riga
def highlight_max(table):
"""
Evidenzia il valore massimo di ogni riga.
"""
highlighted_table = []
for row in table.itertuples(index=True):
row_list = [row.Index] # Includo il numero di topic come prima colonna
max_value = max(row[1:]) # Trovo il massimo nella riga
for value in row[1:]:
if value == max_value:
row_list.append(f"\033[1;34m{value:.4f}\033[0m") # Evidenzia in blu
else:
row_list.append(f"{value:.4f}")
highlighted_table.append(row_list)
return highlighted_table
# Applico l'evidenziazione
highlighted_table = highlight_max(table)
# Preparo l'intestazione della tabella
headers = ["n_topics"] + list(table.columns)
# Colore blu per gli header
blue_headers = [f"\033[94m{header}\033[0m" for header in headers]
print_colored("\nRisultati del Coherence Score (C_v) con evidenziazione dei valori massimi:", "blue")
print(tabulate(highlighted_table, headers=blue_headers, tablefmt="fancy_grid"))
Risultati del Coherence Score (C_v) con evidenziazione dei valori massimi: ╒════════════╤═════════════════════╤═════════════════════╤═════════════════════╤═════════════════════╤════════════════════╕ │ n_topics │ model_vec100_win3 │ model_vec100_win5 │ model_vec200_win3 │ model_vec200_win5 │ model_vec50_win3 │ ╞════════════╪═════════════════════╪═════════════════════╪═════════════════════╪═════════════════════╪════════════════════╡ │ 2 │ 0.7562 │ 0.7411 │ 0.7569 │ 0.7639 │ 0.7638 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 3 │ 0.7526 │ 0.5601 │ 0.6453 │ 0.5375 │ 0.7608 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 4 │ 0.667 │ 0.6081 │ 0.5204 │ 0.6148 │ 0.6396 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 5 │ 0.578 │ 0.6189 │ 0.5869 │ 0.626 │ 0.5702 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 6 │ 0.6531 │ 0.589 │ 0.6575 │ 0.6168 │ 0.6237 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 7 │ 0.6303 │ 0.6398 │ 0.6746 │ 0.6482 │ 0.6777 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 8 │ 0.6281 │ 0.6586 │ 0.6492 │ 0.612 │ 0.6283 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 9 │ 0.6607 │ 0.6629 │ 0.6947 │ 0.6441 │ 0.6354 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 10 │ 0.6214 │ 0.6308 │ 0.6724 │ 0.6038 │ 0.6367 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 15 │ 0.6152 │ 0.6355 │ 0.6521 │ 0.6793 │ 0.6612 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 20 │ 0.6552 │ 0.6582 │ 0.6795 │ 0.6518 │ 0.6471 │ ╘════════════╧═════════════════════╧═════════════════════╧═════════════════════╧═════════════════════╧════════════════════╛
Codice
# Raggruppamento per modello e numero di topic
table = results_df_main.pivot(
index="n_topics",
columns="model_name",
values="silhouette"
)
# Riordino le colonne per chiarezza
table = table[sorted(table.columns)]
# Evidenziazione dei valori più alti in ogni riga
def highlight_max(table):
"""
Evidenzia il valore massimo di ogni riga.
"""
highlighted_table = []
for row in table.itertuples(index=True):
row_list = [row.Index] # Numero di topic come prima colonna
max_value = max(row[1:]) # Valore massimo nella riga
for value in row[1:]:
if value == max_value:
row_list.append(f"\033[1;34m{value:.4f}\033[0m") # Evidenzia in blu
else:
row_list.append(f"{value:.4f}")
highlighted_table.append(row_list)
return highlighted_table
# Applico l'evidenziazione
highlighted_table = highlight_max(table)
# Preparo l'intestazione della tabella
headers = ["n_topics"] + list(table.columns)
# Colore blu per gli header
blue_headers = [f"\033[94m{header}\033[0m" for header in headers]
print_colored("\nRisultati della metrica Silhouette con evidenziazione dei valori massimi:", "blue")
print(tabulate(highlighted_table, headers=blue_headers, tablefmt="fancy_grid"))
Risultati della metrica Silhouette con evidenziazione dei valori massimi: ╒════════════╤═════════════════════╤═════════════════════╤═════════════════════╤═════════════════════╤════════════════════╕ │ n_topics │ model_vec100_win3 │ model_vec100_win5 │ model_vec200_win3 │ model_vec200_win5 │ model_vec50_win3 │ ╞════════════╪═════════════════════╪═════════════════════╪═════════════════════╪═════════════════════╪════════════════════╡ │ 2 │ 0.6166 │ 0.6016 │ 0.6213 │ 0.6031 │ 0.6056 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 3 │ 0.6031 │ 0.5912 │ 0.558 │ 0.5973 │ 0.5863 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 4 │ 0.5216 │ 0.5134 │ 0.5339 │ 0.5039 │ 0.4949 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 5 │ 0.4931 │ 0.3755 │ 0.5074 │ 0.3824 │ 0.478 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 6 │ 0.435 │ 0.3449 │ 0.4417 │ 0.3493 │ 0.4155 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 7 │ 0.4413 │ 0.3469 │ 0.4266 │ 0.3515 │ 0.426 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 8 │ 0.4524 │ 0.3441 │ 0.3666 │ 0.3457 │ 0.3102 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 9 │ 0.4528 │ 0.3309 │ 0.3695 │ 0.3438 │ 0.3121 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 10 │ 0.3494 │ 0.3008 │ 0.3657 │ 0.364 │ 0.3194 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 15 │ 0.2904 │ 0.2217 │ 0.3222 │ 0.2783 │ 0.2588 │ ├────────────┼─────────────────────┼─────────────────────┼─────────────────────┼─────────────────────┼────────────────────┤ │ 20 │ 0.2915 │ 0.2068 │ 0.3219 │ 0.2215 │ 0.2134 │ ╘════════════╧═════════════════════╧═════════════════════╧═════════════════════╧═════════════════════╧════════════════════╛
Grafico del Coherence Score
Codice
plt.figure(figsize=(10, 6))
for model_name in results_df_main["model_name"].unique():
model_data = results_df_main[results_df_main["model_name"] == model_name]
plt.plot(
model_data["n_topics"],
model_data["coherence_c_v"],
marker="o",
label=model_name
)
plt.title("\nCoherence Score (C_v) per Modello e Numero di Topic", fontsize=18)
plt.xlabel("Numero di Topic", fontsize=14, color="#b81414")
plt.ylabel("Coherence Score (C_v)", fontsize=14, color="#b81414")
plt.legend()
plt.grid()
plt.tight_layout()
plt.show()
Grafico per la metrica Silhouette
Codice
plt.figure(figsize=(10, 6))
for model_name in results_df_main["model_name"].unique():
model_data = results_df_main[results_df_main["model_name"] == model_name]
plt.plot(
model_data["n_topics"],
model_data["silhouette"],
marker="o",
label=model_name
)
plt.title("\nSilhouette Score per Modello e Numero di Topic", fontsize=18)
plt.xlabel("Numero di Topic", fontsize=14, color="#b81414")
plt.ylabel("Silhouette Score", fontsize=14, color="#b81414")
plt.legend()
plt.grid()
plt.tight_layout()
plt.show()
Codice
# Trovo i migliori risultati per ogni modello basati su Coherence Score
best_coherence = results_df_main.loc[results_df_main.groupby("model_name")["coherence_c_v"].idxmax()]
# Trovo i migliori risultati per ogni modello basati su Silhouette Score
best_silhouette = results_df_main.loc[results_df_main.groupby("model_name")["silhouette"].idxmax()]
# Formatto i risultati come tabelle
coherence_table = best_coherence[["model_name", "n_topics", "coherence_c_v"]]
silhouette_table = best_silhouette[["model_name", "n_topics", "silhouette"]]
print_colored("\nMigliori configurazioni per Coherence Score:", "blue")
print(tabulate(coherence_table, headers=["Modello", "Numero di Topic", "Coherence Score"], tablefmt="fancy_grid"))
print_colored("\nMigliori configurazioni per Silhouette Score:", "blue")
print(tabulate(silhouette_table, headers=["Modello", "Numero di Topic", "Silhouette Score"], tablefmt="fancy_grid"))
Migliori configurazioni per Coherence Score: ╒════╤═══════════════════╤═══════════════════╤═══════════════════╕ │ │ Modello │ Numero di Topic │ Coherence Score │ ╞════╪═══════════════════╪═══════════════════╪═══════════════════╡ │ 11 │ model_vec100_win3 │ 2 │ 0.756224 │ ├────┼───────────────────┼───────────────────┼───────────────────┤ │ 22 │ model_vec100_win5 │ 2 │ 0.741138 │ ├────┼───────────────────┼───────────────────┼───────────────────┤ │ 33 │ model_vec200_win3 │ 2 │ 0.756923 │ ├────┼───────────────────┼───────────────────┼───────────────────┤ │ 44 │ model_vec200_win5 │ 2 │ 0.763862 │ ├────┼───────────────────┼───────────────────┼───────────────────┤ │ 0 │ model_vec50_win3 │ 2 │ 0.76384 │ ╘════╧═══════════════════╧═══════════════════╧═══════════════════╛ Migliori configurazioni per Silhouette Score: ╒════╤═══════════════════╤═══════════════════╤════════════════════╕ │ │ Modello │ Numero di Topic │ Silhouette Score │ ╞════╪═══════════════════╪═══════════════════╪════════════════════╡ │ 11 │ model_vec100_win3 │ 2 │ 0.616605 │ ├────┼───────────────────┼───────────────────┼────────────────────┤ │ 22 │ model_vec100_win5 │ 2 │ 0.601632 │ ├────┼───────────────────┼───────────────────┼────────────────────┤ │ 33 │ model_vec200_win3 │ 2 │ 0.621298 │ ├────┼───────────────────┼───────────────────┼────────────────────┤ │ 44 │ model_vec200_win5 │ 2 │ 0.603138 │ ├────┼───────────────────┼───────────────────┼────────────────────┤ │ 0 │ model_vec50_win3 │ 2 │ 0.605643 │ ╘════╧═══════════════════╧═══════════════════╧════════════════════╛
Clustering con K-Means per ottenere i vettori delle parole
Dopo aver addestrato uno o più modelli Word2Vec il passo successivo è quello di estrarre i vettori di tutte le parole dai modelli e stampare ad esempio le prime 10 parole del vocabolario per analizzare rapidamente un clustering specifico.
KMeans crea un clustering statico con un numero fisso di cluster scelto in modo arbitrario.
Codice
from scipy.spatial.distance import cosine, euclidean
"""
Itero sui modelli Word2Vec costruiti in precedenza e su più numeri di topic, applicando KMeans per ogni configurazione.
"""
# Numero di topic da testare
n_topics_list = [2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20]
# Lista per salvare i risultati
results_distances = []
# Itero sui modelli
for config in configs:
model_name = f"{config['name']}.model"
print_colored(f"\nAnalisi per il modello: {model_name}", "blue")
# Carico o addestro il modello Word2Vec
if os.path.exists(model_name):
print_colored(f"Caricamento del modello salvato: {model_name}", "red")
word2vec_model = Word2Vec.load(model_name)
else:
print_colored(f"Addestramento del modello: {config['name']}", "blue")
word2vec_model = Word2Vec(
sentences=tokenized_texts,
vector_size=config["vector_size"],
window=config["window"],
min_count=config["min_count"],
workers=multiprocessing.cpu_count(),
sg=config["sg"]
)
word2vec_model.save(model_name)
print_colored(f"Modello salvato come: {model_name}", "red")
vocab_sample = list(word2vec_model.wv.index_to_key)[:10]
print_colored("Vocabolario: " + ", ".join(vocab_sample), "blue")
# Itero sui numeri di topic
for n_topics in n_topics_list:
print_colored(f"\nNumero di Topic: {n_topics}", "blue")
# Estrazione dei vettori delle parole
word_vectors = np.array([word2vec_model.wv[word] for word in word2vec_model.wv.index_to_key])
words = word2vec_model.wv.index_to_key
# Clustering con KMeans
kmeans = KMeans(n_clusters=n_topics, random_state=42)
labels = kmeans.fit_predict(word_vectors)
# Raggruppo le parole per cluster
topics = []
for cluster in range(n_topics):
words_in_cluster = [words[i] for i, label in enumerate(labels) if label == cluster]
topics.append(words_in_cluster[:10]) # Prime 10 parole del topic
for i, topic in enumerate(topics):
print(f" Topic {i + 1}: {' '.join(topic)}")
# Calcolo delle distanze semantiche e salvataggio nei risultati
centroids = kmeans.cluster_centers_
for i in range(n_topics):
for j in range(i + 1, n_topics):
cosine_dist = cosine(centroids[i], centroids[j])
euclidean_dist = euclidean(centroids[i], centroids[j])
results_distances.append({
"model_name": config['name'],
"n_topics": n_topics,
"topic_1": i + 1,
"topic_2": j + 1,
"cosine_similarity": 1 - cosine_dist,
"euclidean_distance": euclidean_dist
})
# Converto i risultati in DataFrame
results_df_distances = pd.DataFrame(results_distances)
# Filtro i risultati per cosine similarity
top_cosine = results_df_distances.sort_values(by="cosine_similarity", ascending=False).head(10) # Top 10
low_cosine = results_df_distances.sort_values(by="cosine_similarity", ascending=True).head(10) # Bottom 10
print_colored("\nTop 10 Cosine Similarity:", "blue")
print(top_cosine)
print_colored("\nBottom 10 Cosine Similarity:", "blue")
print(low_cosine)
Analisi per il modello: model_vec50_win3.model Caricamento del modello salvato: model_vec50_win3.model Vocabolario: com, http, company, price, get, e, www, information, font, email Numero di Topic: 2 Topic 1: proletariat bronco cognitive kenton baseboard catherine metabole swamp demagnify cloudburst Topic 2: com http company price get e www information font email Numero di Topic: 3 Topic 1: proletariat bronco cognitive baseboard catherine metabole swamp demagnify cloudburst buoy Topic 2: company get information please statements stock time new may make Topic 3: com http price e www font email td us nbsp Numero di Topic: 4 Topic 1: right top de oo health strong pain drive body weight Topic 2: company get information email please statements us stock time new Topic 3: com http price e www font td nbsp p height Topic 4: ural tras ects reas rien expe wn vol ume eff Numero di Topic: 5 Topic 1: price get us new one go offer need free service Topic 2: company information email please statements stock time may make use Topic 3: com http e www font td nbsp p height size Topic 4: top de oo strong drive age mr st city america Topic 5: ural rien wn vol ume eff ger srge smallcap gs Numero di Topic: 6 Topic 1: service market inc business say international million high gas first Topic 2: company information statements stock time may make use look within Topic 3: com http www font td nbsp p height size width Topic 4: top de leave head la ca female solid ce un Topic 5: smallcap penls tier marketpiace eshopkey zwallet barreis chevron futureevents mw Topic 6: price get e email please us new one go offer Numero di Topic: 7 Topic 1: service market inc business say products international million high gas Topic 2: get e email please us new one use go offer Topic 3: com http www font td nbsp p height size width Topic 4: top de st leave die head usb wireless fat la Topic 5: smallcap penls tier grecian marketpiace eshopkey jdz zwallet barreis chevron Topic 6: price v windows microsoft software professional office xp adobe system Topic 7: company information statements stock time may make look within report Numero di Topic: 8 Topic 1: nds spe mitosis quadrant eagle relaxation madras meson miliennium bra Topic 2: br right top de oo strong drive body age st Topic 3: injections cute doom rn slutty agaln thieve gall anthropomorphism ie Topic 4: service market inc business say international million internet high call Topic 5: font td nbsp p height size width b align tr Topic 6: company information statements stock may make use look within report Topic 7: com http e www email please message r send u Topic 8: price get us time new one go offer need free Numero di Topic: 9 Topic 1: nds spe mitosis quadrant eagle relaxation madras meson miliennium bra Topic 2: p br right top de oo strong body age st Topic 3: injections cute doom rn slutty agaln thieve gall anthropomorphism ie Topic 4: one service market inc business say products international million internet Topic 5: price x v windows microsoft software professional office xp adobe Topic 6: company information statements stock may make use look within report Topic 7: com http e www email please us message r send Topic 8: get time new go offer need free pills money take Topic 9: font td nbsp height size width b align tr color Numero di Topic: 10 Topic 1: brendan sri nat brrating bd nds wor spe mitosis quadrant Topic 2: top power age mr city lead design wait data music Topic 3: injections cute doom rn slutty agaln thieve gall anthropomorphism ie Topic 4: e p r b u c x v n th Topic 5: price windows microsoft software professional office xp adobe system cd Topic 6: company information statements stock may make look within report investment Topic 7: com http www email please us message free send mail Topic 8: one use go service market inc business account say news Topic 9: font td nbsp height size width align tr color face Topic 10: get time new offer need pills money take order want Numero di Topic: 15 Topic 1: bra ural tim tras ects reas saf rien expe kno Topic 2: power control computer support age mr enter city case card Topic 3: rn duve mexican crtc htmlbody wl tp boys internetstore zdrive Topic 4: get us time one use go offer need free money Topic 5: information stock within report investment securities provide act trade advice Topic 6: statements may make look result future number forward could base Topic 7: email please message send mail contact click remove account link Topic 8: company service market include inc business say news share international Topic 9: font td nbsp height size width align tr color face Topic 10: new pills order online best save also available ship viagra Topic 11: price windows microsoft software professional office xp adobe system cd Topic 12: br top de oo strong drive body st id leave Topic 13: e p r b u c x v n th Topic 14: com http www computron net info src nd html index Topic 15: fw beman compete beach respecter durrell influential california wound player Numero di Topic: 20 Topic 1: smallcap penls tier grecian marketpiace yasser eshopkey jdz zwallet barreis Topic 2: increase well two program industry network hold credit control experience Topic 3: rn crtc htmlbody zdrive goto poliomyelitis fingernail conceal macedonia kenney Topic 4: right second power meet computer support enter type city case Topic 5: windows microsoft professional office xp adobe cd ms pro mx Topic 6: statements may look result future forward could base risk believe Topic 7: email please message send mail contact click remove line list Topic 8: time make one use go take want account like say Topic 9: font td nbsp height width align tr border href src Topic 10: price get us new offer need money order work online Topic 11: software system download drive draw suite ibm pc creative dvd Topic 12: top de oo st die digital head usb wireless fat Topic 13: e p r b u c x v n th Topic 14: size color face br family strong body leave rnd alt Topic 15: nat lon congratulatory apr wow brrating satellite tri thu heal Topic 16: information stock within report investment securities provide act trade advice Topic 17: age mr data dr sport est jan sun europe africa Topic 18: pills viagra cialis last soft hours per health mg pain Topic 19: com http www free computron link net info stop html Topic 20: company service market include inc business news share international million Analisi per il modello: model_vec100_win3.model Caricamento del modello salvato: model_vec100_win3.model Vocabolario: com, http, company, price, get, e, www, information, font, email Numero di Topic: 2 Topic 1: zero proletariat emotional bronco cognitive baseboard catherine bramble metabole swamp Topic 2: com http company price get e www information font email Numero di Topic: 3 Topic 1: zero proletariat emotional bronco cognitive baseboard catherine bramble metabole swamp Topic 2: company get information email please statements us stock time new Topic 3: com http price e www font td nbsp p height Numero di Topic: 4 Topic 1: ural tim ects reas saf ire vol ume eff ger Topic 2: company price get information email please statements us stock time Topic 3: com http e www font td nbsp p height size Topic 4: increase right top de oo health strong pain power computer Numero di Topic: 5 Topic 1: top de strong age mr st city lead leave data Topic 2: company information email please statements stock time may make use Topic 3: com http e www font td nbsp p height size Topic 4: price get us new one go offer need free service Topic 5: mirrior smallcap shaun conservative gs verizon nl penls scan johnson Numero di Topic: 6 Topic 1: top de leave la ca female solid ce und white Topic 2: price get e email please us new one go offer Topic 3: com http www font td nbsp p height size width Topic 4: service market inc business say products international million high gas Topic 5: smallcap penls walter amende reaily prlces eshopkey fu balustrade futureevents Topic 6: company information statements stock time may make use look within Numero di Topic: 7 Topic 1: top de body leave fat la ca female solid ce Topic 2: price get us new one offer need free pills money Topic 3: http www font td nbsp p height size width b Topic 4: go service market inc business say international million high call Topic 5: smallcap penls walter amende reaily prlces eshopkey fu balustrade destroy Topic 6: com e email please message r send mail contact click Topic 7: company information statements stock time may make use look within Numero di Topic: 8 Topic 1: smallcap penls scan walter amende reaily prlces fa eshopkey fu Topic 2: com http e www email please message free r send Topic 3: get us time new one go offer need pills money Topic 4: service market inc business say international million high br gas Topic 5: price x v windows microsoft software professional office xp adobe Topic 6: company information statements stock may make use look within report Topic 7: font td nbsp p height size width b align tr Topic 8: top de body st leave head fat la ca gb Numero di Topic: 9 Topic 1: smallcap penls scan walter amende reaily prlces fa eshopkey fu Topic 2: email please message send mail contact click remove account link Topic 3: get us time new one go offer need free pills Topic 4: service market inc business say international million high gas first Topic 5: price windows microsoft software professional office xp adobe system cd Topic 6: company information statements stock may make use look within report Topic 7: font td nbsp height size width align tr color face Topic 8: top de body leave head fat la ca female solid Topic 9: com http e www p r b u c computron Numero di Topic: 10 Topic 1: stipulate earthquake brendan nat brec nds wor spe mitosis quadrant Topic 2: information email please message send mail contact click remove account Topic 3: get us time new offer need free pills money take Topic 4: one use go service market inc business say news international Topic 5: price windows microsoft software professional office xp adobe system cd Topic 6: company statements stock may make look within report investment include Topic 7: font td nbsp height size width align tr color face Topic 8: br right top de oo strong drive body power age Topic 9: com http e www p r b u c computron Topic 10: khumalo injections bf spitfire rn etcmore slutty stereo fre limerick Numero di Topic: 15 Topic 1: tim ects vol ume eff italian mirrior smallcap shaun stoxo Topic 2: email please message send mail contact click remove link line Topic 3: pills order online best save many also today available ship Topic 4: increase power control age mr enter city case open lead Topic 5: price windows microsoft software professional office xp adobe system cd Topic 6: statements time may make look result future number forward could Topic 7: font td nbsp height size width align tr color face Topic 8: br right top de strong drive body st id leave Topic 9: e p r b u c x v n th Topic 10: injections rn duve centertable var valliuum telecom funky zodiac goto Topic 11: get us new one use go offer need money take Topic 12: information stock within report investment securities provide act trade advice Topic 13: company service market include inc business account news share international Topic 14: fw confront dovekie influential ec crania novelty flight wink brendan Topic 15: com http www free computron net info visit html index Numero di Topic: 20 Topic 1: vol ume eff mirrior smallcap shaun stoxo conservative anchorite qui Topic 2: email please message send mail contact click remove link net Topic 3: pills order online best save many also today available ship Topic 4: service market inc business international million high gas state oil Topic 5: price windows microsoft software professional office xp adobe system cd Topic 6: statements may look result future forward could base risk performance Topic 7: font td nbsp height size width align tr color face Topic 8: influential ec flight wel con mon tx radio tournament karpenkov Topic 9: e p r b u c x v n th Topic 10: injections rn duve centertable valliuum telecom funky zodiac goto retiree Topic 11: get new one go offer need money take want work Topic 12: information stock within report investment securities account provide act trade Topic 13: company time make use include number news share pay interest Topic 14: power age mr enter case open lead build property large Topic 15: free computron stop visit show change fax via deal sale Topic 16: com http www border href src nd index php image Topic 17: right oo drive city music die digital head usb load Topic 18: us lot ibm creative canon sony toshiba viewsonic robotics aopen Topic 19: line info br html top de china body st type Topic 20: strong fat female integrate und white dosage black spring class Analisi per il modello: model_vec100_win5.model Caricamento del modello salvato: model_vec100_win5.model Vocabolario: com, http, company, price, get, e, www, information, font, email Numero di Topic: 2 Topic 1: font p size b align color face br center style Topic 2: com http company price get e www information email please Numero di Topic: 3 Topic 1: top de strong leave die digital head benefit dr fat Topic 2: company get information email please statements us stock time new Topic 3: com http price e www font td nbsp p height Numero di Topic: 4 Topic 1: de leave die ca female solid integrate un und white Topic 2: get us new one go offer need free service market Topic 3: company information email please statements stock time may make use Topic 4: com http price e www font td nbsp p height Numero di Topic: 5 Topic 1: family top transfer de oo w china strong body power Topic 2: company information statements stock may make look within report service Topic 3: price get e email please us time new one use Topic 4: com http www font td nbsp p height size width Topic 5: smallcap gs promethe dilute grecian pricess greenbriar fm amateur balustrade Numero di Topic: 6 Topic 1: content family top ms de strong body st bill leave Topic 2: one use go service market inc business say number products Topic 3: com http www font td nbsp p height size width Topic 4: price get e us time new offer need free pills Topic 5: smallcap gs grecian abzt accent khumalo dainty draftsman noneedl hs Topic 6: company information email please statements stock may make look message Numero di Topic: 7 Topic 1: p b family top ms de strong body st leave Topic 2: one use go service market inc business say number news Topic 3: com e email please us message free r send u Topic 4: price get time new offer need pills money take c Topic 5: smallcap gs grecian abzt futureevents accent khumalo dainty draftsman noneedl Topic 6: company information statements stock may make look within report investment Topic 7: http www font td nbsp height size width align tr Numero di Topic: 8 Topic 1: top de strong body leave die digital head benefit wireless Topic 2: price x v windows microsoft software professional office xp adobe Topic 3: one use service market inc business say products international million Topic 4: smallcap gs grecian abzt futureevents accent khumalo draftsman noneedl accuse Topic 5: com http e www email please p message r b Topic 6: font td nbsp height size width align tr color face Topic 7: get us time new go offer need free pills money Topic 8: company information statements stock may make look within report investment Numero di Topic: 9 Topic 1: top strong digital benefit dr storage female solid ed integrate Topic 2: price windows microsoft software professional office xp adobe system project Topic 3: one use service market inc business say news products international Topic 4: gs grecian accent khumalo jj tt noneedl hs accuse injections Topic 5: com email please us message free send mail contact click Topic 6: www font td nbsp height width align tr color face Topic 7: get time new go offer need pills money take order Topic 8: company information statements stock may make look within report investment Topic 9: http e p size r b u c x v Numero di Topic: 10 Topic 1: strong die female solid integrate white dosage black port spring Topic 2: price windows microsoft software professional office xp adobe system full Topic 3: first top transfer think china power computer support age mr Topic 4: gs satisfactory khumalo noneedl injections specialist maryland prevention pike cigarettes Topic 5: com email please message send mail contact click remove account Topic 6: www font td nbsp height width align tr color face Topic 7: get us time new one go offer need free pills Topic 8: information statements stock may make look within report investment securities Topic 9: http e p size r b u c x v Topic 10: company use service market include inc business say number news Numero di Topic: 15 Topic 1: nascar motor indianapolis ne silicon flight tie diverse abuse craft Topic 2: windows microsoft software professional office xp adobe special system full Topic 3: say first think china power computer support age mr enter Topic 4: fre anodic valiumxanaxcialis ie graywacke dru duve mexican govenment htmlbody Topic 5: price may news products expect believe project term show next Topic 6: font td nbsp height width align tr color face border Topic 7: get time new one go offer need free pills money Topic 8: company information stock within report investment include securities provide act Topic 9: com http e p r b u c x v Topic 10: statements make look result future number forward could base risk Topic 11: email please us message send mail contact click remove account Topic 12: br top strong body leave die head usb load wireless Topic 13: www computron via cs duty ali lot epson tel zone Topic 14: size family female solid integrate und dosage black spring class Topic 15: use service market inc business share international million internet high Numero di Topic: 20 Topic 1: flight zenith iv salaam bequest allot adventure muller abet flatulent Topic 2: windows software professional office xp adobe system cd ms pro Topic 3: strong digital benefit light dr sport air se fire art Topic 4: fre anodic valiumxanaxcialis graywacke dru duve mexican govenment htmlbody boys Topic 5: price may news products expect believe project term show next Topic 6: font td nbsp height width align tr color face border Topic 7: get new go offer need money take order want work Topic 8: statements look future forward mean fact action events estimate involve Topic 9: http e p r b u c x v n Topic 10: time make include result number without pay could base interest Topic 11: email please message send mail contact click remove link net Topic 12: pills viagra cialis drug soft meds hours health brand mg Topic 13: com www free computron dollars fax via sale duty ali Topic 14: size family female solid integrate und dosage black spring class Topic 15: service market inc business share international million high gas oil Topic 16: microsoft cs lot epson intel ibm creative canon sony toshiba Topic 17: say first think power control age enter city case lead Topic 18: company information stock within report investment securities provide act trade Topic 19: br top body type leave die head usb wireless ca Topic 20: us one use account would thank call give stop state Analisi per il modello: model_vec200_win3.model Caricamento del modello salvato: model_vec200_win3.model Vocabolario: com, http, company, price, get, e, www, information, font, email Numero di Topic: 2 Topic 1: proletariat emotional bronco superb cognitive baseboard catherine bramble metabole swamp Topic 2: com http company price get e www information font email Numero di Topic: 3 Topic 1: relaxation madras meson ural hou ects reas rien expe kno Topic 2: com http www font td nbsp p height size width Topic 3: company price get e information email please statements us stock Numero di Topic: 4 Topic 1: increase right top de oo health strong pain drive weight Topic 2: com http e www font td nbsp p height size Topic 3: company price get information email please statements us stock time Topic 4: wn leaden vol asp eff ger mmsr dividend hookup mirrior Numero di Topic: 5 Topic 1: right top de strong pain drive weight power age mr Topic 2: com http e www font td nbsp p height size Topic 3: company information email please statements stock time may make use Topic 4: mmsr smallcap shaun limitation gs nl penls scan elide johnson Topic 5: price get us new one go offer need free service Numero di Topic: 6 Topic 1: top de leave female solid ce und dosage black pi Topic 2: market inc business say international million high gas first system Topic 3: company information statements stock may make use look within report Topic 4: smallcap df abzt marketpiace gram ipod alpine khumalo incumbent raleigh Topic 5: price get e email please us time new one go Topic 6: com http www font td nbsp p height size width Numero di Topic: 7 Topic 1: female und dosage black edit pop silver las debug wilson Topic 2: market inc business million high gas first energy increase well Topic 3: company information statements stock may make use look within report Topic 4: smallcap ipod khumalo raleigh noneedl hs injections dystrophy qi silence Topic 5: get e email please us time new one go offer Topic 6: com http www font td nbsp p height size width Topic 7: price x v windows microsoft software professional office xp adobe Numero di Topic: 8 Topic 1: twit prosaic chalcocite bridegroom acquisitive kinesic emma stipulate earthquake invidious Topic 2: b br right top de strong body power age mr Topic 3: injections blur pike induce rn slutty aeruginosa stereo fre bankrupt Topic 4: e information email please stock message within report send investment Topic 5: com http www font td nbsp height size width computron Topic 6: company statements time may make look result future number forward Topic 7: price us p offer pills r u c order online Topic 8: get new one use go need free service money market Numero di Topic: 9 Topic 1: twit dupe conciliatory prosaic chalcocite bridegroom acquisitive kinesic emma apace Topic 2: th br right top de strong pain body power age Topic 3: injections blur pike induce rn slutty aeruginosa stereo fre bankrupt Topic 4: com http e www email please us message free r Topic 5: font td nbsp height size width b align tr color Topic 6: statements may make look result future number forward could base Topic 7: price p offer pills u c save x v n Topic 8: get time new one use go need service money market Topic 9: company information stock within report investment include securities account news Numero di Topic: 10 Topic 1: acquisitive stipulate earthquake invidious sri spe mitosis quadrant flatulent eagle Topic 2: br right top de oo strong drive body power age Topic 3: injections blur pike induce rn slutty aeruginosa fre bankrupt limerick Topic 4: information email please message send mail contact click remove account Topic 5: font td nbsp height size width b align tr color Topic 6: company statements stock may make look within report investment include Topic 7: price v windows microsoft software professional office xp adobe system Topic 8: get us time new offer need pills money take order Topic 9: one use go service market inc work business say number Topic 10: com http e www p free r u c computron Numero di Topic: 15 Topic 1: asp ger mmsr dividend hookup mirrior wakey smallcap shaun stoxo Topic 2: power computer support age mr enter city case card lead Topic 3: injections induce fre duve mexican boys internetstore thindata eo telecom Topic 4: company make use include account number news share pay interest Topic 5: http www font td nbsp height width align tr color Topic 6: statements may look result future forward could base risk performance Topic 7: pills save viagra cialis drug soft meds hours per paliourg Topic 8: service market inc business say international million high gas first Topic 9: information stock within report investment securities provide act trade advice Topic 10: e p r b u c x v n th Topic 11: price windows microsoft software professional office xp adobe system cd Topic 12: com email please message send mail contact click remove computron Topic 13: get us time new one go offer need free money Topic 14: size info br html right family top de china strong Topic 15: dosage spring alone pop silver conversion vegas triple motor explore Numero di Topic: 20 Topic 1: asp mmsr dividend hookup mirrior wakey smallcap shaun stoxo ladies Topic 2: power computer support age mr enter city case card open Topic 3: injections fre duve mexican boys internetstore eo telecom zdrive zodiac Topic 4: company make use include account news share pay interest expect Topic 5: font td nbsp height size width align tr color face Topic 6: may result future number could base risk performance fact due Topic 7: price us offer need free money order online best save Topic 8: service market inc business international million high gas oil energy Topic 9: information stock report investment securities provide trade advice invest newsletter Topic 10: e p r b c x v n g l Topic 11: windows microsoft software professional office xp adobe system cd ms Topic 12: email please message send mail contact click remove link list Topic 13: get time new one go take want work like say Topic 14: br right top de strong drive body st leave die Topic 15: spring alone pop silver conversion triple explore fw wilson zero Topic 16: net line html content paliourg mobile text federal type format Topic 17: statements look within forward act section mean contain understand material Topic 18: u products th without dollars change canada pass property usa Topic 19: com http www computron info src nd fax index via Topic 20: pills viagra cialis soft hours per health mg hi pain Analisi per il modello: model_vec200_win5.model Caricamento del modello salvato: model_vec200_win5.model Vocabolario: com, http, company, price, get, e, www, information, font, email Numero di Topic: 2 Topic 1: font p size b align tr color face href pt Topic 2: com http company price get e www information email please Numero di Topic: 3 Topic 1: de strong city leave die digital head benefit dr co Topic 2: company get information email please statements us stock time new Topic 3: com http price e www font td nbsp p height Numero di Topic: 4 Topic 1: de leave die ca female solid integrate belize un und Topic 2: company information email please statements stock time may make use Topic 3: com http price e www font td nbsp p height Topic 4: get us new one go offer need free market take Numero di Topic: 5 Topic 1: line family top de oo china strong mobile body power Topic 2: company information statements stock may make use look within report Topic 3: com http www font td nbsp p height size width Topic 4: price get e email please us time new one go Topic 5: gs picnic penls beget grecian df greenbriar walter amende bisque Numero di Topic: 6 Topic 1: b line content family top de china strong mobile body Topic 2: company information email please statements stock may make look message Topic 3: com http www font td nbsp p height size width Topic 4: price get e us time new one go offer need Topic 5: gs grecian abzt walter thatexpress futureevents khumalo dainty noneedl column Topic 6: use service market inc business say number news international million Numero di Topic: 7 Topic 1: b family top de w china k strong body age Topic 2: company information statements stock may make look within report investment Topic 3: com e email please message r send u mail c Topic 4: price get us time new go offer need free pills Topic 5: gs grecian abzt thatexpress futureevents khumalo dainty noneedl column colloquy Topic 6: one use service market inc business say number news international Topic 7: http www font td nbsp p height size width align Numero di Topic: 8 Topic 1: b th f top de china strong body st city Topic 2: company information statements stock may make look within report investment Topic 3: service market inc business say news products international million high Topic 4: gs grecian abzt thatexpress khumalo dainty noneedl column colloquy upper Topic 5: com http www font td nbsp p height size width Topic 6: get e email please us time new one use go Topic 7: pills r c order online best save many also n Topic 8: price u x v windows microsoft software professional info office Numero di Topic: 9 Topic 1: top china strong body st city leave die digital head Topic 2: company information statements stock may look within report investment include Topic 3: service market inc business news products international million high gas Topic 4: gs grecian khumalo dainty noneedl column upper injections cute dystrophy Topic 5: font td nbsp height size width align tr color face Topic 6: get email please us time new make one use go Topic 7: pills order online best save many also today available ship Topic 8: e p r b c x v n windows software Topic 9: com http price www free u contact computron link net Numero di Topic: 10 Topic 1: b line th br family de china strong body la Topic 2: company information statements stock may look within report investment include Topic 3: service market inc business say news products international million high Topic 4: gs beget grecian walter amende bisque bedridden claremont debate khumalo Topic 5: font td nbsp height size width align tr color face Topic 6: get e email please us time new make one use Topic 7: pills order online best save many also today available ship Topic 8: p r c x v n windows microsoft software professional Topic 9: com http price www u contact computron net list dollars Topic 10: top st city leave music die digital head benefit dr Numero di Topic: 15 Topic 1: solid integrate und white dosage black spring alone pop silver Topic 2: information statements may look within report investment include securities result Topic 3: company stock service market inc business news provide share international Topic 4: gs khumalo noneedl upper injections maryland bf prevention soil compiiance Topic 5: td height width align tr border href src nd pt Topic 6: get us time new make one use go offer need Topic 7: pills ship viagra cialis drug soft prescription meds hours paliourg Topic 8: font nbsp p size b line color face br center Topic 9: e r u c v n th without g l Topic 10: say first program transfer part power country control computer support Topic 11: http x info f de oo w php k biz Topic 12: com www computron dollars fax via sale duty ali lot Topic 13: email please message send mail contact click remove account link Topic 14: price windows microsoft software professional office xp adobe system cd Topic 15: age city digital benefit dr reduce ed bottom movies jan Numero di Topic: 20 Topic 1: female solid integrate und dosage black spring shell alone pop Topic 2: statements may look within report investment securities result future forward Topic 3: company stock service market include inc business news provide share Topic 4: dru duve mexican htmlbody wl boys internetstore dolars funky goto Topic 5: td height width align tr border href src nd pt Topic 6: get time new make one use go money take want Topic 7: pills viagra cialis soft hours health mg pain weight tabs Topic 8: font nbsp size color face br center style family strong Topic 9: u th without change title notice canada pass property usa Topic 10: program transfer part fund country support age mr enter view Topic 11: die head usb co ca cable storage bite front un Topic 12: com www free computron dollars fax via sale duty ali Topic 13: information email please message send mail contact click remove account Topic 14: http line info html top index php image china biz Topic 15: city digital benefit dr channel ed bottom picture jan kill Topic 16: price us offer need order online best save products many Topic 17: windows microsoft software professional office xp adobe system cd ms Topic 18: e p r b c x v n g l Topic 19: ne flight nat foot zenith anne bequest allot adventure muller Topic 20: high energy increase well year industry network power control computer Top 10 Cosine Similarity: model_name n_topics topic_1 topic_2 cosine_similarity \ 271 model_vec50_win3 20 1 3 0.999990 166 model_vec50_win3 15 1 3 0.999989 1417 model_vec200_win3 7 1 4 0.999986 738 model_vec100_win3 20 1 10 0.999970 633 model_vec100_win3 15 1 10 0.999962 1402 model_vec200_win3 6 1 4 0.999948 1651 model_vec200_win3 20 1 3 0.999932 483 model_vec100_win3 6 1 5 0.999921 1546 model_vec200_win3 15 1 3 0.999910 1192 model_vec100_win5 20 1 4 0.999907 euclidean_distance 271 0.211988 166 0.259208 1417 0.451314 738 0.246665 633 0.252614 1402 0.484643 1651 0.263208 483 0.501343 1546 0.268195 1192 0.261026 Bottom 10 Cosine Similarity: model_name n_topics topic_1 topic_2 cosine_similarity \ 2148 model_vec200_win5 20 3 5 0.308221 1278 model_vec100_win5 20 6 10 0.323022 2134 model_vec200_win5 20 2 8 0.323541 2033 model_vec200_win5 15 3 5 0.323814 1934 model_vec200_win5 9 2 5 0.329272 1971 model_vec200_win5 10 2 5 0.334939 2021 model_vec200_win5 15 2 5 0.335520 2151 model_vec200_win5 20 3 8 0.339583 2131 model_vec200_win5 20 2 5 0.343459 1309 model_vec100_win5 20 8 16 0.343964 euclidean_distance 2148 4.483481 1278 4.087314 2134 3.707233 2033 4.350453 1934 3.948797 1971 4.048055 2021 4.572542 2151 3.230401 2131 4.629296 1309 4.488446
Esplorazione e visualizzazione dei dati ottenuti con t-SNE e UMAP
Codice
from sklearn.manifold import TSNE
from umap.umap_ import UMAP
import random
# Numero massimo di parole visualizzate
max_words = 150
# Itero sui modelli
for config in configs:
model_name = f"{config['name']}.model"
print_colored(f"\n\n\nVisualizzazione per il modello: {model_name}", "blue")
# Carico il modello salvato
if os.path.exists(model_name):
word2vec_model = Word2Vec.load(model_name)
else:
print(f"Modello non trovato: {model_name}")
continue
# Campiono casualmente un sottoinsieme di parole
words = random.sample(word2vec_model.wv.index_to_key, min(max_words, len(word2vec_model.wv.index_to_key)))
word_vectors = np.array([word2vec_model.wv[word] for word in words])
print("\nEsecuzione di t-SNE...\n")
tsne = TSNE(n_components=2, random_state=42)
reduced_vectors_tsne = tsne.fit_transform(word_vectors)
plt.figure(figsize=(10, 10))
plt.scatter(reduced_vectors_tsne[:, 0], reduced_vectors_tsne[:, 1], alpha=0.6)
for i, word in enumerate(words):
plt.annotate(word, (reduced_vectors_tsne[i, 0], reduced_vectors_tsne[i, 1]), fontsize=8)
plt.title(f"t-SNE: {model_name}", fontsize=18)
plt.xticks(fontsize=14, color="#b81414")
plt.yticks(fontsize=14, color="#b81414")
plt.show()
print()
print("\nEsecuzione di UMAP...\n")
umap_reducer = UMAP(random_state=42)
reduced_vectors_umap = umap_reducer.fit_transform(word_vectors)
plt.figure(figsize=(10, 10))
plt.scatter(reduced_vectors_umap[:, 0], reduced_vectors_umap[:, 1], alpha=0.6)
for i, word in enumerate(words):
plt.annotate(word, (reduced_vectors_umap[i, 0], reduced_vectors_umap[i, 1]), fontsize=8)
plt.title(f"UMAP: {model_name}", fontsize=18)
plt.xticks(fontsize=14, color="#b81414")
plt.yticks(fontsize=14, color="#b81414")
plt.show()
print()
Visualizzazione per il modello: model_vec50_win3.model
Esecuzione di t-SNE...
Esecuzione di UMAP...
Visualizzazione per il modello: model_vec100_win3.model
Esecuzione di t-SNE...
Esecuzione di UMAP...
Visualizzazione per il modello: model_vec100_win5.model
Esecuzione di t-SNE...
Esecuzione di UMAP...
Visualizzazione per il modello: model_vec200_win3.model
Esecuzione di t-SNE...
Esecuzione di UMAP...
Visualizzazione per il modello: model_vec200_win5.model
Esecuzione di t-SNE...
Esecuzione di UMAP...
Scelta dei modelli
La scelta del modello e del numero di topic dipende dall'obiettivo dell'analisi:
- Individuazione dei Topic Principali -
L'obiettivo è identificare chiaramente i topic principali con elevata coerenza semantica. Il criterio di selezione seguito è stato quello di scegliere il miglior modello basato sul Coherence Score per misurare la coerenza semantica delle parole all'interno dei topic. Un punteggio alto del Coherence Score indica che le parole del topic sono semanticamente correlate e rappresentano un concetto chiaro.
- Calcolo della distanza Semantica -
L'obiettivo è quello di valutare le distanze semantiche tra i topic, utile per capire quanto sono correlati o distinti. Il criterio di selezione seguito è stato quello di scegliere il miglior modello basato sulla metrica di Silhouette la quale indica quanto i cluster sono distanti tra loro. Per questo obiettivo, ci interessa che i cluster abbiano una buona separazione, dato che vogliamo analizzare le distanze semantiche tra i topic.
Il Coherence Score deve essere accettabile per garantire che i topic siano semanticamente significativi ma non è prioritario.
- Analisi Contenutistica Approfondita -
L'obiettivo è quello di estrarre un numero elevato di topic per effettuare un'analisi approfondita dei contenuti. La metrica utilizzata per scegliere il modello è stato il Coherence Score, fondamentale per assicurarsi che i topic siano semanticamente coerenti, dato che l'analisi deve riflettere accuratamente i temi principali. Anche con molti topic occorre un punteggio di coerenza elevato per garantire che ogni gruppo di parole sia significativo.
Il Silhouette Score è meno importante, perché con un numero elevato di topic, i cluster tendono naturalmente a sovrapporsi.
- Valutazione dell'eterogeneità -
L'obiettivo è misurare quanto i topic siano diversi tra loro, cioè quanto siano ben separati semanticamente. La metrica utilizzata è la Silhouette per misurare quanto i cluster (topic) siano ben separati. Un punteggio alto indica che i topic sono distinti e ben definiti. Questo è cruciale per valutare l'eterogeneità, dato che stiamo misurando la separazione tra i topic.
Codice
models_to_use = {
"Individuare Topic Principali": {"model_name": "model_vec200_win5", "n_topics": 2},
"Calcolare Distanza Semantica": {"model_name": "model_vec200_win3", "n_topics": 2},
"Analisi Contenutistica": {"model_name": "model_vec200_win5", "n_topics": 15},
"Valutare Eterogeneità": {"model_name": "model_vec200_win3", "n_topics": 5}
}
# Itero e applico il modello corrispondente
for objective, config in models_to_use.items():
model_name = f"{config['model_name']}.model"
print_colored(f"\n{objective}, {model_name}", "blue")
# Carico il modello Word2Vec
word2vec_model = Word2Vec.load(model_name)
# Estrazione dei vettori
word_vectors = np.array([word2vec_model.wv[word] for word in word2vec_model.wv.index_to_key])
words = word2vec_model.wv.index_to_key
# Clustering K-Means
n_topics = config["n_topics"]
kmeans = KMeans(n_clusters=n_topics, random_state=42)
labels = kmeans.fit_predict(word_vectors)
# Analisi specifica
if objective == "Individuare Topic Principali":
for cluster in range(n_topics):
words_in_cluster = [words[i] for i, label in enumerate(labels) if label == cluster]
print(f"Topic {cluster + 1}: {' '.join(words_in_cluster[:10])}")
elif objective == "Calcolare Distanza Semantica":
centroids = kmeans.cluster_centers_
for i in range(n_topics):
for j in range(i + 1, n_topics):
cosine_sim = 1 - cosine(centroids[i], centroids[j])
print(f"Distanza Cosine tra Topic {i + 1} e Topic {j + 1}: {cosine_sim:.4f}")
elif objective == "Analisi Contenutistica":
for cluster in range(n_topics):
words_in_cluster = [words[i] for i, label in enumerate(labels) if label == cluster]
print(f"Analisi approfondita del Topic {cluster + 1}: {' '.join(words_in_cluster[:15])}")
elif objective == "Valutare Eterogeneità":
# Recupero il Silhouette Score da results_df
filtered_df = results_df_main[
(results_df_main["model_name"] == config["model_name"]) & (results_df_main["n_topics"] == n_topics)
]
if filtered_df.empty:
print(f"⚠️ Nessun dato trovato per il modello: {config['model_name']} con {n_topics} topic.")
silhouette_avg = None
else:
silhouette_avg = filtered_df["silhouette"].values[0]
print(f"Silhouette Score (da results_df_main): {silhouette_avg:.4f}")
Individuare Topic Principali, model_vec200_win5.model Topic 1: font p size b align tr color face href pt Topic 2: com http company price get e www information email please Calcolare Distanza Semantica, model_vec200_win3.model Distanza Cosine tra Topic 1 e Topic 2: 0.9802 Analisi Contenutistica, model_vec200_win5.model Analisi approfondita del Topic 1: solid integrate und white dosage black spring alone pop silver conversion triple nascar motor camera Analisi approfondita del Topic 2: information statements may look within report investment include securities result future forward act could base Analisi approfondita del Topic 3: company stock service market inc business news provide share international million high gas trade expect Analisi approfondita del Topic 4: gs khumalo noneedl upper injections maryland bf prevention soil compiiance spark rn etcmore slutty agaln Analisi approfondita del Topic 5: td height width align tr border href src nd pt style index bgcolor gif cs Analisi approfondita del Topic 6: get us time new make one use go offer need free money take order want Analisi approfondita del Topic 7: pills ship viagra cialis drug soft prescription meds hours paliourg health brand mg hi less Analisi approfondita del Topic 8: font nbsp p size b line color face br center html family top image china Analisi approfondita del Topic 9: e r u c v n th without g l section h change title notice Analisi approfondita del Topic 10: say first program transfer part power country control computer support mr enter view case open Analisi approfondita del Topic 11: http x info f de oo w php k biz st type id die head Analisi approfondita del Topic 12: com www computron dollars fax via sale duty ali lot epson tel zone intel exactly Analisi approfondita del Topic 13: email please message send mail contact click remove account link net list receive address reply Analisi approfondita del Topic 14: price windows microsoft software professional office xp adobe system cd ms pro download drive retail Analisi approfondita del Topic 15: age city digital benefit dr reduce ed bottom movies jan either red kill sun green Valutare Eterogeneità, model_vec200_win3.model Silhouette Score (da results_df_main): 0.5074
Per quanto riguarda l'individuazione dei topic principali contenuti dalle email SPAM, l'output è rappresentativo dei contenuti generali di formattazione HTML e di termini associati a comunicazioni aziendali.
Il valore della distanza semantica è molto elevato indicando che esiste una forte similarità semantica. I due topic hanno contenuti sovrapponibili provenienti da contesti simili.
Per quanto riguarda l'analisi contenuntistica approfondita, il modello scelto può essere sfruttato per identificare categorie specifiche di contenuti spam.
L'eterogeneità dei contenuti è moderata indicando che i cluster non sono completamente separati.
Word Cloud
Codice
from wordcloud import WordCloud
import matplotlib.pyplot as plt
# Seleziono i modelli scelti
selected_models = [
{"model_name": "model_vec200_win5.model", "n_topics": 2, "description": "Topic Principali"},
{"model_name": "model_vec200_win3.model", "n_topics": 2, "description": "Calcolo della Distanza Semantica"},
{"model_name": "model_vec200_win5.model", "n_topics": 15, "description": "Analisi Contenutistica"},
{"model_name": "model_vec200_win3.model", "n_topics": 5, "description": "Valutazione dell’Eterogeneità"},
]
# Itero sui modelli selezionati
for model_config in selected_models:
model_name = model_config["model_name"]
n_topics = model_config["n_topics"]
description = model_config["description"]
print_colored(f"\n\n\n\nGenerazione Word Cloud per il modello: {model_name}", "blue")
# Carico il modello salvato
word2vec_model = Word2Vec.load(model_name)
# Estraggo i topic con KMeans
word_vectors = np.array([word2vec_model.wv[word] for word in word2vec_model.wv.index_to_key])
words = word2vec_model.wv.index_to_key
kmeans = KMeans(n_clusters=n_topics, random_state=42)
labels = kmeans.fit_predict(word_vectors)
# Imposto la griglia per le nuvole di parole
cols = 2 # Numero di colonne
rows = (n_topics + 1) // cols # Numero di righe
fig, axes = plt.subplots(rows, cols, figsize=(12, rows * 4))
axes = axes.flatten()
# Genero una Word Cloud per ciascun topic
for cluster in range(n_topics):
words_in_cluster = [words[i] for i, label in enumerate(labels) if label == cluster]
topic_words = " ".join(words_in_cluster[:50]) # Uso solo le prime 50 parole
# Genero la Word Cloud
wordcloud = WordCloud(
width=800, height=400, background_color="white", max_words=50, colormap="viridis"
).generate(topic_words)
# Subplot
ax = axes[cluster]
ax.imshow(wordcloud, interpolation="bilinear")
ax.axis("off")
ax.set_title(f"Topic {cluster + 1}", fontsize=14, color="#b81414")
# Nascondo subplot vuoti
for ax in axes[n_topics:]:
ax.axis("off")
fig.suptitle(f"{description}\n", fontsize=22)
plt.tight_layout()
plt.show()
Generazione Word Cloud per il modello: model_vec200_win5.model
Generazione Word Cloud per il modello: model_vec200_win3.model
Generazione Word Cloud per il modello: model_vec200_win5.model
Generazione Word Cloud per il modello: model_vec200_win3.model
Rappresentazione della Distanza Semantica
t-SNE è uno strumento utile per rappresentare visivamente le distanze semantiche, per esplorare relazioni tra parole, concetti e cluster.
Può ridurre a 2 o 3 dimensioni i vettori ad alta dimensionalità dei modelli Word2Vec.
Funziona bene per dataset piccoli
Codice
from sklearn.manifold import TSNE
selected_models = [
{"model_name": "model_vec200_win5.model", "n_topics": 2, "description": "Topic Principali"},
{"model_name": "model_vec200_win3.model", "n_topics": 2, "description": "Calcolo della Distanza Semantica"},
{"model_name": "model_vec200_win5.model", "n_topics": 15, "description": "Analisi Contenutistica"},
{"model_name": "model_vec200_win3.model", "n_topics": 5, "description": "Valutazione dell’Eterogeneità"},
]
# Visualizzazione con t-SNE per ogni modello selezionato
for model_config in selected_models:
model_name = model_config["model_name"]
n_topics = model_config["n_topics"]
description = model_config["description"]
print_colored(f"\n\nGenerazione t-SNE per il modello: {model_name} ({description})", "blue")
# Carico il modello Word2Vec
word2vec_model = Word2Vec.load(model_name)
word_vectors = np.array([word2vec_model.wv[word] for word in word2vec_model.wv.index_to_key])
words = word2vec_model.wv.index_to_key
# Clustering con KMeans
kmeans = KMeans(n_clusters=n_topics, random_state=42)
labels = kmeans.fit_predict(word_vectors)
# Riduzione dimensionale con t-SNE
tsne = TSNE(n_components=2, random_state=42)
reduced_vectors = tsne.fit_transform(word_vectors)
plt.figure(figsize=(10, 8))
for i in range(n_topics):
cluster_points = reduced_vectors[labels == i]
plt.scatter(cluster_points[:, 0], cluster_points[:, 1], label=f"Topic {i + 1}")
plt.title(f"\nVisualizzazione dei Topic con t-SNE ({description})", fontsize=18)
plt.xticks(fontsize=14, color="#b81414")
plt.yticks(fontsize=14, color="#b81414")
plt.legend()
plt.show()
Generazione t-SNE per il modello: model_vec200_win5.model (Topic Principali)
Generazione t-SNE per il modello: model_vec200_win3.model (Calcolo della Distanza Semantica)
Generazione t-SNE per il modello: model_vec200_win5.model (Analisi Contenutistica)
Generazione t-SNE per il modello: model_vec200_win3.model (Valutazione dell’Eterogeneità)
Radar plot
Codice
from math import pi
metrics = {
"Coherence": [0.756923, 0.7639, 0.5869, 0.6793],
"Silhouette": [0.621298, 0.6031, 0.5074, 0.2783],
"Topic": [2, 2, 15, 5],
"Model": ["model_vec200_win3", "model_vec200_win5", "model_vec200_win3_dup", "model_vec200_win5_dup"],
}
labels = metrics["Model"] # Etichette dei modelli
df_metrics = pd.DataFrame(metrics).set_index("Model") # Imposto "Model" come indice
# Radar plot
angles = np.linspace(0, 2 * np.pi, len(df_metrics.columns), endpoint=False).tolist()
angles += angles[:1]
fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True))
# Iterazione sulle righe del DataFrame
for idx, row in df_metrics.iterrows():
values = row.tolist() + row.tolist()[:1] # Chiudo il radar plot
ax.plot(angles, values, label=idx)
ax.fill(angles, values, alpha=0.25)
ax.set_yticks([])
ax.set_xticks(angles[:-1])
ax.set_xticklabels(df_metrics.columns)
plt.title("Radar Plot dei Modelli", fontsize=16, pad=20)
ax.legend(bbox_to_anchor=(1.2, 1.05))
plt.tight_layout()
plt.show()
Email NON SPAM
Estrazione dalle email NON SPAM di informazioni sulle Organizzazioni menzionate
Codice
print_colored("Dataset iniziale droppato","blue")
print(df_email_dropped.head())
Dataset iniziale droppato
text label_num
0 Subject: enron methanol ; meter # : 988291\nth... 0
1 Subject: hpl nom for january 9 , 2001\n( see a... 0
2 Subject: neon retreat\nho ho ho , we ' re arou... 0
3 Subject: photoshop , windows , office . cheap ... 1
4 Subject: re : indian springs\nthis deal is to ... 0
Codice
df_email_dropped_ham = df_email_dropped[df_email_dropped['label_num'] == 0]
print_colored("Dataset droppato contenente solo email NON SPAM", "blue")
print(df_email_dropped_ham.head())
Dataset droppato contenente solo email NON SPAM
text label_num
0 Subject: enron methanol ; meter # : 988291\nth... 0
1 Subject: hpl nom for january 9 , 2001\n( see a... 0
2 Subject: neon retreat\nho ho ho , we ' re arou... 0
4 Subject: re : indian springs\nthis deal is to ... 0
5 Subject: ehronline web address change\nthis me... 0
Analizzo il contenuto delle prime 10 email per comprendere il corpus e il contesto, al fine di definire il flusso di lavoro successivo
Codice
for idx, email in enumerate(df_email_dropped_ham['text'].head(10), 1):
print_colored(f"Email {idx}", "blue")
print(email)
print("\n")
Email 1 Subject: enron methanol ; meter # : 988291 this is a follow up to the note i gave you on monday , 4 / 3 / 00 { preliminary flow data provided by daren } . please override pop ' s daily volume { presently zero } to reflect daily activity you can obtain from gas control . this change is needed asap for economics purposes . Email 2 Subject: hpl nom for january 9 , 2001 ( see attached file : hplnol 09 . xls ) - hplnol 09 . xls Email 3 Subject: neon retreat ho ho ho , we ' re around to that most wonderful time of the year - - - neon leaders retreat time ! i know that this time of year is extremely hectic , and that it ' s tough to think about anything past the holidays , but life does go on past the week of december 25 through january 1 , and that ' s what i ' d like you to think about for a minute . on the calender that i handed out at the beginning of the fall semester , the retreat was scheduled for the weekend of january 5 - 6 . but because of a youth ministers conference that brad and dustin are connected with that week , we ' re going to change the date to the following weekend , january 12 - 13 . now comes the part you need to think about . i think we all agree that it ' s important for us to get together and have some time to recharge our batteries before we get to far into the spring semester , but it can be a lot of trouble and difficult for us to get away without kids , etc . so , brad came up with a potential alternative for how we can get together on that weekend , and then you can let me know which you prefer . the first option would be to have a retreat similar to what we ' ve done the past several years . this year we could go to the heartland country inn ( www . . com ) outside of brenham . it ' s a nice place , where we ' d have a 13 - bedroom and a 5 - bedroom house side by side . it ' s in the country , real relaxing , but also close to brenham and only about one hour and 15 minutes from here . we can golf , shop in the antique and craft stores in brenham , eat dinner together at the ranch , and spend time with each other . we ' d meet on saturday , and then return on sunday morning , just like what we ' ve done in the past . the second option would be to stay here in houston , have dinner together at a nice restaurant , and then have dessert and a time for visiting and recharging at one of our homes on that saturday evening . this might be easier , but the trade off would be that we wouldn ' t have as much time together . i ' ll let you decide . email me back with what would be your preference , and of course if you ' re available on that weekend . the democratic process will prevail - - majority vote will rule ! let me hear from you as soon as possible , preferably by the end of the weekend . and if the vote doesn ' t go your way , no complaining allowed ( like i tend to do ! ) have a great weekend , great golf , great fishing , great shopping , or whatever makes you happy ! bobby Email 4 Subject: re : indian springs this deal is to book the teco pvr revenue . it is my understanding that teco just sends us a check , i haven ' t received an answer as to whether there is a predermined price associated with this deal or if teco just lets us know what we are giving . i can continue to chase this deal down if you need . Email 5 Subject: ehronline web address change this message is intended for ehronline users only . due to a recent change to ehronline , the url ( aka " web address " ) for accessing ehronline needs to be changed on your computer . the change involves adding the letter " s " to the " http " reference in the url . the url for accessing ehronline should be : https : / / ehronline . enron . com . this change should be made by those who have added the url as a favorite on the browser . Email 6 Subject: spring savings certificate - take 30 % off save 30 % when you use our customer appreciation spring savings certificate at foot locker , lady foot locker , kids foot locker and at our online stores ! welcome to our customer appreciation spring savings certificate ! use the special certificate below and receive 30 % off your purchases either in our stores or online . hurry ! this 4 - day sale begins thursday , march 22 and ends sunday , march 25 . share the savings today and e - mail this offer to your friends . many items already are reduced and the 30 % discount is taken off the lowest sale price . click below to print your customer appreciation spring savings certificate . you must present this coupon at any foot locker , lady foot locker or kids foot locker store in the u . s . foot locker canada is not participating in this program . ready , set , save ! our spring savings discount will automatically appear when you use the links below or type camlem 21 into the promotion code box during checkout . footlocker . com certificate code : camlem 21 ladyfootlocker . com certificate code : camlem 21 kidsfootlocker . com certificate code : camlem 21 remember , returns are hassle - free . simply bring your items to any of our stores nationwide or through the mail . don ' t be left out - register today to learn about our new products , promotions , events and other specials . simply click below . terms and conditions . some exclusions apply , please see manager for complete details . certificate must be presented at the time of purchase and cannot be used in conjunction with any other discount offer or associate benefit . not redeemable for cash . applicable taxes must be paid by bearer . cannot be applied to prior purchases or to gift card purchases . void where prohibited , licensed or regulated . catalog exclusions apply . valid thursday , 3 / 22 / 01 through sunday , 3 / 25 / 01 . foot locker canada will not participate in this program . if you do not wish to receive future emails please click below to unsubscribe : Email 7 Subject: noms / actual flow for 2 / 26 we agree - - - - - - - - - - - - - - - - - - - - - - forwarded by melissa jones / texas utilities on 02 / 27 / 2001 10 : 33 am - - - - - - - - - - - - - - - - - - - - - - - - - - - " eileen ponton " on 02 / 27 / 2001 09 : 46 : 26 am to : david avila / lsp / enserch / us @ tu , charlie stone / texas utilities @ tu , melissa jones / texas utilities @ tu , hpl . scheduling @ enron . com , liz . bellamy @ enron . com cc : subject : noms / actual flow for 2 / 26 date nom flow - mcf flow - mmbtu 2 / 26 / 01 0 456 469 btu = 1 . 027 Email 8 Subject: nominations for oct . 21 - 23 , 2000 ( see attached file : hplnl 021 . xls ) - hplnl 021 . xls Email 9 Subject: enron / hpl actuals for august 28 , 2000 teco tap 20 . 000 / enron ; 120 . 000 / hpl gas daily ls hpl lsk ic 20 . 000 / enron Email 10 Subject: tenaska iv july darren : please remove the price on the tenaska iv sale , deal 384258 , for july and enter the demand fee . the amount should be $ 3 , 902 , 687 . 50 . thanks , megan
Prima prova di estrazione delle entità dalle email con tutte le etichette riconosciute da SpaCy per avere un'idea più generale delle informazioni riguardanti le Organizzazioni utilizzando en_core_web_sm
Codice
# Carico il modello NER pre-addestrato
nlp = spacy.load("en_core_web_sm")
# Filtro le email NON SPAM
df_email_dropped_ham = df_email_dropped[df_email_dropped['label_num'] == 0]['text']
# Lista per salvare le entità rilevanti
all_entities = []
for email in df_email_dropped_ham:
doc = nlp(email) # Applico NER a ciascuna email
relevant_entities = [
ent.text for ent in doc.ents if ent.label_ in {"ORG", "PERSON", "GPE", "NORP", "FAC","LOC", "PRODUCT", "EVENT", "WORK_OF_ART", "LAW",
"LANGUAGE", "DATE", "TIME", "PERCENT", "MONEY","QUANTITY", "ORDINAL", "CARDINAL", "WORK_OF_ART", "LAW"
}
]
all_entities.append(relevant_entities)
for idx, entities in enumerate(all_entities[:10]):
print_colored(f"Email {idx + 1} - Entità rilevanti:", "blue")
print({', '.join(entities) if entities else 'Nessuna'})
Email 1 - Entità rilevanti: {'enron methanol, 988291, monday, daily, zero, daily'} Email 2 - Entità rilevanti: {'january 9 , 2001, 09, xls, 09'} Email 3 - Entità rilevanti: {'ho ho ho, january 1, a minute, the weekend of january 5 - 6, that week, the following weekend, january 12 - 13, the spring semester, that weekend, first, the past several years, this year, 13, 5, only about one hour and 15 minutes, saturday, sunday morning, second, houston, saturday, evening, that weekend, the end of the weekend, doesn, a great weekend, bobby'} Email 4 - Entità rilevanti: {'indian'} Email 5 - Entità rilevanti: {'Nessuna'} Email 6 - Entità rilevanti: {'spring, 30 %, 30 %, spring, kids foot locker, spring, 30 %, 4 - day, thursday, march 22, sunday, march 25, today, the 30 %, spring, the u ., foot locker canada, spring, 21, 21, 21, 21, don, today, bearer, thursday, 3 / 22 / 01, foot locker canada'} Email 7 - Entità rilevanti: {'2 / 26, melissa jones / texas, 02 / 27 / 2001, 10, 33, 02 / 27 / 2001 09, 46, 26, david avila, charlie, melissa, texas, 2 / 26, 2 / 26 / 01, 1, 027'} Email 8 - Entità rilevanti: {'oct . 21 - 23 , 2000, 021, xls, 021'} Email 9 - Entità rilevanti: {'august 28 , 2000, 20, 000, 120, daily, 20, 000'} Email 10 - Entità rilevanti: {'tenaska, july, tenaska, july, 3, 902, 687, 50'}
Seconda prova di estrazione utilizzando solo l'etichetta ORG per avere un'idea più precisa sulle Organizzazioni utilizzando en_core_web_sm
Codice
# Carico il modello NER
nlp = spacy.load("en_core_web_sm")
# Filtro le email NON SPAM
df_email_dropped_ham = df_email_dropped[df_email_dropped['label_num'] == 0]['text']
# Lista per salvare le entità
all_organizations = []
for email in df_email_dropped_ham:
doc = nlp(email) # Applico NER
# Filtro solo "ORG" e rimuovo entità con numeri
organizations = [
ent.text for ent in doc.ents if ent.label_ == "ORG" and not any(char.isdigit() for char in ent.text)
]
all_organizations.append(set(organizations)) # Evito duplicati all'interno della stessa email
for idx, orgs in enumerate(all_organizations[:50]): # Mostro solo le prime 50 email
print(f"Email {idx + 1} - Organizzazioni menzionate: {', '.join(orgs) if orgs else 'Nessuna'}")
Email 1 - Organizzazioni menzionate: Nessuna Email 2 - Organizzazioni menzionate: xls Email 3 - Organizzazioni menzionate: Nessuna Email 4 - Organizzazioni menzionate: Nessuna Email 5 - Organizzazioni menzionate: Nessuna Email 6 - Organizzazioni menzionate: bearer, foot locker canada Email 7 - Organizzazioni menzionate: Nessuna Email 8 - Organizzazioni menzionate: xls Email 9 - Organizzazioni menzionate: Nessuna Email 10 - Organizzazioni menzionate: Nessuna Email 11 - Organizzazioni menzionate: christy sweeney / hou, darron c giron / hou, riley / hou /, mary m smith / hou /, zivley / hou, austin / hou /, nathan l hlavaty / hou Email 12 - Organizzazioni menzionate: riley / hou /, mike morris / corp / enron @ Email 13 - Organizzazioni menzionate: boas / hou Email 14 - Organizzazioni menzionate: Nessuna Email 15 - Organizzazioni menzionate: Nessuna Email 16 - Organizzazioni menzionate: Nessuna Email 17 - Organizzazioni menzionate: xls Email 18 - Organizzazioni menzionate: Nessuna Email 19 - Organizzazioni menzionate: Nessuna Email 20 - Organizzazioni menzionate: Nessuna Email 21 - Organizzazioni menzionate: Nessuna Email 22 - Organizzazioni menzionate: Nessuna Email 23 - Organizzazioni menzionate: neuweiler / hou Email 24 - Organizzazioni menzionate: the houston expl, megan parker / corp / enron Email 25 - Organizzazioni menzionate: Nessuna Email 26 - Organizzazioni menzionate: cst, the enron corp . Email 27 - Organizzazioni menzionate: lozano / hou, north america corp ., the texas gas group Email 28 - Organizzazioni menzionate: Nessuna Email 29 - Organizzazioni menzionate: Nessuna Email 30 - Organizzazioni menzionate: Nessuna Email 31 - Organizzazioni menzionate: ami chokshi / corp / enron @ enron , ami chokshi / corp / enron Email 32 - Organizzazioni menzionate: Nessuna Email 33 - Organizzazioni menzionate: doc Email 34 - Organizzazioni menzionate: Nessuna Email 35 - Organizzazioni menzionate: zivley / hou, cico oil & gas Email 36 - Organizzazioni menzionate: Nessuna Email 37 - Organizzazioni menzionate: devers @ columbia, jen black, nyu, michelle, abercrombie, trisha, brenda, sutton, daniel, syscom - inc ., canedy, janelle mccan Email 38 - Organizzazioni menzionate: Nessuna Email 39 - Organizzazioni menzionate: Nessuna Email 40 - Organizzazioni menzionate: Nessuna Email 41 - Organizzazioni menzionate: pg & e, pg & e texas, pg & e texas bulletin board, pg &, sherlyn Email 42 - Organizzazioni menzionate: Nessuna Email 43 - Organizzazioni menzionate: lone star Email 44 - Organizzazioni menzionate: Nessuna Email 45 - Organizzazioni menzionate: Nessuna Email 46 - Organizzazioni menzionate: Nessuna Email 47 - Organizzazioni menzionate: wagner brown Email 48 - Organizzazioni menzionate: aquila Email 49 - Organizzazioni menzionate: Nessuna Email 50 - Organizzazioni menzionate: chevron
Terza prova di estrazione utilizzando solo l'etichetta ORG ma questa volta utilizzando en_core_web_trf
Codice
torch.cuda.empty_cache() # Libera la memoria inutilizzata
torch.cuda.set_per_process_memory_fraction(0.8, device=0)
# Configurazione per l'allocazione della memoria
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = (
"expandable_segments," # Permette all'allocatore di utilizzare segmenti di memoria espandibili per
# ridurre la frammentazione e migliorare la gestione della memoria
"garbage_collection_threshold:0.75," #Specifica la soglia di utilizzo della memoria per
# avviare la raccolta dei frammenti non utilizzati
"release_cuda_memory:True," # Permette di rilasciare memoria GPU inutilizzata automaticamente durante il runtime
"device_allocator_retry:True" # Consente di gestire errori di allocazione riprovando una nuova
# allocazione dopo aver svuotato la memoria non utilizzata
)
cuda_memory_summary = torch.cuda.memory_summary(device=None, abbreviated=True)
print_colored(cuda_memory_summary, "")
# Configuro SpaCy per usare la GPU
set_gpu_allocator("pytorch") # Usa PyTorch come backend per l'allocazione
require_gpu() # Forzo l'uso della GPU
nlp = spacy.load("en_core_web_trf")
# Verifico se la GPU è in uso
gpu_status = spacy.prefer_gpu()
if gpu_status:
print_colored("GPU utilizzata con successo.\n", "blue")
else:
print_colored("SpaCy sta utilizzando la CPU.", "blue")
# Filtro le email NON SPAM
df_email_dropped_ham = df_email_dropped[df_email_dropped['label_num'] == 0]['text']
# Lista per salvare le entità
all_organizations = []
for email in df_email_dropped_ham:
doc = nlp(email) # Applica NER
# Filtro solo "ORG" e rimuovo entità con numeri
organizations = [
ent.text for ent in doc.ents if ent.label_ == "ORG" and not any(char.isdigit() for char in ent.text)
]
all_organizations.append(set(organizations)) # Evito duplicati all'interno della stessa email
for idx, orgs in enumerate(all_organizations[:50]):
print_colored(f"\nEmail {idx + 1} - Organizzazioni estratte:", "blue")
print({', '.join(orgs) if orgs else 'Nessuna'})
|===========================================================================| | PyTorch CUDA memory summary, device ID 0 | |---------------------------------------------------------------------------| | CUDA OOMs: 0 | cudaMalloc retries: 0 | |===========================================================================| | Metric | Cur Usage | Peak Usage | Tot Alloc | Tot Freed | |---------------------------------------------------------------------------| | Allocated memory | 245257 KiB | 948 MiB | 1188 MiB | 948 MiB | |---------------------------------------------------------------------------| | Active memory | 245257 KiB | 948 MiB | 1188 MiB | 948 MiB | |---------------------------------------------------------------------------| | Requested memory | 243802 KiB | 946 MiB | 1184 MiB | 946 MiB | |---------------------------------------------------------------------------| | GPU reserved memory | 462848 KiB | 1040 MiB | 1040 MiB | 602112 KiB | |---------------------------------------------------------------------------| | Non-releasable memory | 217590 KiB | 231012 KiB | 1135 MiB | 923 MiB | |---------------------------------------------------------------------------| | Allocations | 79 | 300 | 379 | 300 | |---------------------------------------------------------------------------| | Active allocs | 79 | 300 | 379 | 300 | |---------------------------------------------------------------------------| | GPU reserved segments | 27 | 50 | 50 | 23 | |---------------------------------------------------------------------------| | Non-releasable allocs | 27 | 39 | 99 | 72 | |---------------------------------------------------------------------------| | Oversize allocations | 0 | 0 | 0 | 0 | |---------------------------------------------------------------------------| | Oversize GPU segments | 0 | 0 | 0 | 0 | |===========================================================================| GPU utilizzata con successo. Email 1 - Organizzazioni estratte: {'pop'} Email 2 - Organizzazioni estratte: {'Nessuna'} Email 3 - Organizzazioni estratte: {'Nessuna'} Email 4 - Organizzazioni estratte: {'teco'} Email 5 - Organizzazioni estratte: {'Nessuna'} Email 6 - Organizzazioni estratte: {'kidsfootlocker . com, footlocker . com, foot locker canada'} Email 7 - Organizzazioni estratte: {'enron, enserch, texas utilities, tu'} Email 8 - Organizzazioni estratte: {'Nessuna'} Email 9 - Organizzazioni estratte: {'hpl gas daily'} Email 10 - Organizzazioni estratte: {'tenaska iv'} Email 11 - Organizzazioni estratte: {'sitara, svcs, enron, ees'} Email 12 - Organizzazioni estratte: {'swift, enronxgate'} Email 13 - Organizzazioni estratte: {'volume mgmt, none\n'} Email 14 - Organizzazioni estratte: {'eops'} Email 15 - Organizzazioni estratte: {'enron, cc'} Email 16 - Organizzazioni estratte: {'concorde churchill, equistar channelview'} Email 17 - Organizzazioni estratte: {'Nessuna'} Email 18 - Organizzazioni estratte: {'Nessuna'} Email 19 - Organizzazioni estratte: {'enron, cc, texas utilities, hpl, tu, teco, enron . com, iferc'} Email 20 - Organizzazioni estratte: {'spinner . com, spinner'} Email 21 - Organizzazioni estratte: {'hpl, aep'} Email 22 - Organizzazioni estratte: {'enron, logitech, houston, european resolution center, north american resolution center'} Email 23 - Organizzazioni estratte: {'sitara, valero'} Email 24 - Organizzazioni estratte: {'the houston exploration, the houston exploration company, danny'} Email 25 - Organizzazioni estratte: {'iferc'} Email 26 - Organizzazioni estratte: {'vanguard lifestrategy, the enron corp, cst, enron'} Email 27 - Organizzazioni estratte: {'enron north america corp, cc, the texas gas group, ect, eol'} Email 28 - Organizzazioni estratte: {'Nessuna'} Email 29 - Organizzazioni estratte: {'Nessuna'} Email 30 - Organizzazioni estratte: {'Nessuna'} Email 31 - Organizzazioni estratte: {'cc, copanos'} Email 32 - Organizzazioni estratte: {'kcs energy, hpl\n, cc, hpl, bob withers, lst rev'} Email 33 - Organizzazioni estratte: {'fuel supply, archer\n'} Email 34 - Organizzazioni estratte: {'iferc'} Email 35 - Organizzazioni estratte: {'vance, cico oil & gas co'} Email 36 - Organizzazioni estratte: {'sitara, cc, samson lone star, svcs, hesco gathering oil co, winn exploration co, hesco, period\n'} Email 37 - Organizzazioni estratte: {'strategicweather, aol . com, launidadlatina, syscom - inc ., related . com, newyorklife . com, erac, stevens - tech, bigfoot, jpmorgan . com, stern . nyu, stern, delinvest, excite, summitbank, aol ., huntoon . com, usa, philamuseum, get, yahoo . com, gap, gap store, advanstar . com'} Email 38 - Organizzazioni estratte: {'Nessuna'} Email 39 - Organizzazioni estratte: {'Nessuna'} Email 40 - Organizzazioni estratte: {'enron, the enrononline product control group, enrononline'} Email 41 - Organizzazioni estratte: {'pg & e, legal, deal, hpl, desk, ena, pg & e texas, pg'} Email 42 - Organizzazioni estratte: {'Nessuna'} Email 43 - Organizzazioni estratte: {"tenaska iv ', lone star, cornhusker - lone star payments"} Email 44 - Organizzazioni estratte: {'hpl gas daily'} Email 45 - Organizzazioni estratte: {'enron, enserch, texas utilities, tu'} Email 46 - Organizzazioni estratte: {'sitara, just, equistar'} Email 47 - Organizzazioni estratte: {'enron, tufco, txu'} Email 48 - Organizzazioni estratte: {'aquila dallas marketing, epgt, unify, it and business group, aquila marketing, el paso'} Email 49 - Organizzazioni estratte: {'ehronline'} Email 50 - Organizzazioni estratte: {'sitara, cc, gas settlements, houston pipe line co, hsc _ flw, enronxgate, ect, chevron phillips chemical co, enron . com, hplc, dfarmer'}
Raggruppamento dei contenuti delle email
Codice
# Raggruppamento delle organizzazioni in una lista unica
flattened_organizations = [org for orgs in all_organizations for org in orgs]
# Conto le occorrenze di ogni organizzazione
org_counter = Counter(flattened_organizations)
df_organizations = pd.DataFrame.from_dict(org_counter, orient='index', columns=['Frequenza']).reset_index()
df_organizations.rename(columns={'index': 'Organizzazione'}, inplace=True)
df_organizations['Tipo'] = 'Da categorizzare'
df_organizations['Fonti'] = 'Da compilare'
df_organizations = df_organizations.sort_values(by='Frequenza', ascending=False).reset_index(drop=True)
print_colored("Raggruppamento dei contenuti delle email NON SPAM in un DataFrame ordinato per frequenza\n", "blue")
print(df_organizations)
Raggruppamento dei contenuti delle email NON SPAM in un DataFrame ordinato per frequenza
Organizzazione Frequenza Tipo Fonti
0 enron 580 Da categorizzare Da compilare
1 cc 387 Da categorizzare Da compilare
2 hpl 273 Da categorizzare Da compilare
3 sitara 249 Da categorizzare Da compilare
4 ect 240 Da categorizzare Da compilare
... ... ... ... ...
3154 pioneer exploration 1 Da categorizzare Da compilare
3155 maytag 1 Da categorizzare Da compilare
3156 sears 1 Da categorizzare Da compilare
3157 sears . com 1 Da categorizzare Da compilare
3158 ft 1 Da categorizzare Da compilare
[3159 rows x 4 columns]
Codice
# Raggruppamento delle organizzazioni in una lista unica
flattened_organizations = [org for orgs in all_organizations for org in orgs]
org_counter = Counter(flattened_organizations)
df_organizations = pd.DataFrame.from_dict(org_counter, orient='index', columns=['Frequenza']).reset_index()
df_organizations.rename(columns={'index': 'Organizzazione'}, inplace=True)
df_organizations['Tipo'] = 'Da categorizzare'
df_organizations['Fonti'] = 'Da compilare'
df_organizations = df_organizations.sort_values(by='Frequenza', ascending=False).reset_index(drop=True)
# Configuro Pandas per non troncare le righe
pd.set_option('display.max_rows', None)
print_colored("Raggruppamento dei contenuti delle email NON SPAM in un DataFrame ordinato per frequenza\n", "blue")
print(df_organizations.iloc[0:35])
Raggruppamento dei contenuti delle email NON SPAM in un DataFrame ordinato per frequenza
Organizzazione Frequenza Tipo \
0 enron 580 Da categorizzare
1 cc 387 Da categorizzare
2 hpl 273 Da categorizzare
3 sitara 249 Da categorizzare
4 ect 240 Da categorizzare
5 ena 142 Da categorizzare
6 eastrans 96 Da categorizzare
7 tu 94 Da categorizzare
8 hplc 91 Da categorizzare
9 texas utilities 86 Da categorizzare
10 unify 86 Da categorizzare
11 enron . com 80 Da categorizzare
12 enron north america corp 80 Da categorizzare
13 tenaska iv 76 Da categorizzare
14 enronxgate 63 Da categorizzare
15 wellhead 48 Da categorizzare
16 duke 46 Da categorizzare
17 entex 44 Da categorizzare
18 equistar 43 Da categorizzare
19 tenaska 43 Da categorizzare
20 txu 41 Da categorizzare
21 deal 39 Da categorizzare
22 pops 39 Da categorizzare
23 tufco 36 Da categorizzare
24 enserch 35 Da categorizzare
25 teco 35 Da categorizzare
26 enron capital & trade resources corp 34 Da categorizzare
27 midcon 33 Da categorizzare
28 aep 32 Da categorizzare
29 gas 32 Da categorizzare
30 north america corp 31 Da categorizzare
31 pec 31 Da categorizzare
32 fuels cotton valley 30 Da categorizzare
33 ces 29 Da categorizzare
34 pg & e 29 Da categorizzare
Fonti
0 Da compilare
1 Da compilare
2 Da compilare
3 Da compilare
4 Da compilare
5 Da compilare
6 Da compilare
7 Da compilare
8 Da compilare
9 Da compilare
10 Da compilare
11 Da compilare
12 Da compilare
13 Da compilare
14 Da compilare
15 Da compilare
16 Da compilare
17 Da compilare
18 Da compilare
19 Da compilare
20 Da compilare
21 Da compilare
22 Da compilare
23 Da compilare
24 Da compilare
25 Da compilare
26 Da compilare
27 Da compilare
28 Da compilare
29 Da compilare
30 Da compilare
31 Da compilare
32 Da compilare
33 Da compilare
34 Da compilare
Scatter plot con riduzione della dimensionalità tramite t-SNE
Le dimensioni delle bolle sono proporzionali alla frequenza delle organizzazioni
Rappresentazione delle prime 35 Organizzazioni con 5 cluster in due dimensioni
Codice
from sklearn.feature_extraction.text import TfidfVectorizer
# Dati iniziali
orgs = df_organizations['Organizzazione'].values
frequenze = df_organizations['Frequenza'].values
# Converto i dati in rappresentazioni numeriche
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(orgs)
# Applico clustering
n_clusters = 5 # Numero di cluster desiderati
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
clusters = kmeans.fit_predict(X)
# Riduzione dimensionale per la visualizzazione
tsne = TSNE(n_components=2, random_state=42)
X_embedded = tsne.fit_transform(X.toarray())
df_organizations['Cluster'] = clusters
cluster_names = []
for cluster_id in range(n_clusters):
cluster_orgs = df_organizations[df_organizations['Cluster'] == cluster_id].sort_values(by='Frequenza', ascending=False)['Organizzazione']
top_keywords = ", ".join(cluster_orgs.head(35)) # Prime 35 organizzazioni come rappresentanti
cluster_names.append(f"Cluster {cluster_id}: {top_keywords}")
# Definizione dei colori delle bolle
colors = plt.cm.get_cmap("tab10", n_clusters).colors
# Visualizzo i risultati con un grafico scatter
plt.figure(figsize=(40, 40))
scatter_points = [] # Per gestire i punti scatter
scatter_labels = [] # Per gestire le etichette delle legende
# Creo i grafici scatter
for cluster_id in range(n_clusters):
# Filtro i punti del cluster corrente
cluster_mask = clusters == cluster_id
cluster_points = X_embedded[cluster_mask]
scatter = plt.scatter(
cluster_points[:, 0],
cluster_points[:, 1],
s=frequenze[cluster_mask] * 70, # Dimensioni proporzionali alla frequenza
c=[colors[cluster_id]],
alpha=0.7,
edgecolors='black'
)
scatter_points.append(scatter)
scatter_labels.append(cluster_names[cluster_id])
plt.title("\nRappresentazione delle prime 35 Organizzazioni con 5 cluster", fontsize=62)
plt.xlabel("\nt-SNE Dimension x", fontsize=52)
plt.ylabel("t-SNE Dimension y", fontsize=52)
plt.xticks(ha='right', fontsize=46, color='#b81414')
plt.yticks(ha='right', fontsize=46, color='#b81414')
plt.grid(True)
plt.tight_layout()
plt.show()
Rappresentazione delle prime 35 Organizzazioni con 20 cluster in due dimensioni
Codice
orgs = df_organizations['Organizzazione'].values
frequenze = df_organizations['Frequenza'].values
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(orgs)
n_clusters = 20
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
clusters = kmeans.fit_predict(X)
tsne = TSNE(n_components=2, random_state=42)
X_embedded = tsne.fit_transform(X.toarray())
df_organizations['Cluster'] = clusters
cluster_names = []
for cluster_id in range(n_clusters):
cluster_orgs = df_organizations[df_organizations['Cluster'] == cluster_id].sort_values(by='Frequenza', ascending=False)['Organizzazione']
top_keywords = ", ".join(cluster_orgs.head(35)) # Prime 35 organizzazioni come rappresentanti
cluster_names.append(f"Cluster {cluster_id}: {top_keywords}")
colors = plt.cm.get_cmap("tab10", n_clusters).colors
plt.figure(figsize=(40, 40))
scatter_points = [] # Per gestire i punti scatter
scatter_labels = [] # Per gestire le etichette delle legende
for cluster_id in range(n_clusters):
# Filtro i punti del cluster corrente
cluster_mask = clusters == cluster_id
cluster_points = X_embedded[cluster_mask]
scatter = plt.scatter(
cluster_points[:, 0],
cluster_points[:, 1],
s=frequenze[cluster_mask] * 70,
c=[colors[cluster_id]],
alpha=0.7,
edgecolors='black'
)
scatter_points.append(scatter)
scatter_labels.append(cluster_names[cluster_id])
plt.title("\nRappresentazione delle prime 35 Organizzazioni con 20 cluster", fontsize=62)
plt.xlabel("\nt-SNE Dimension x", fontsize=52)
plt.ylabel("t-SNE Dimension y", fontsize=52)
plt.xticks(ha='right', fontsize=46, color='#b81414')
plt.yticks(ha='right', fontsize=46, color='#b81414')
plt.grid(True)
plt.tight_layout()
plt.show()
Rappresentando un numero maggiore di cluster in uno scatter plot con riduzione della dimensionalità tramite t-SNE, si ottiene una visione più dettagliata dell'eterogeneità dei dati.
Rappresentazione delle prime 35 Organizzazioni con 20 cluster in 3 dimensioni
Codice
orgs = df_organizations['Organizzazione'].values
frequenze = df_organizations['Frequenza'].values
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(orgs)
n_clusters = 20
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
clusters = kmeans.fit_predict(X)
tsne = TSNE(n_components=3, random_state=42)
X_embedded = tsne.fit_transform(X.toarray())
df_organizations['Cluster'] = clusters
cluster_names = []
for cluster_id in range(n_clusters):
cluster_orgs = df_organizations[df_organizations['Cluster'] == cluster_id].sort_values(by='Frequenza', ascending=False)['Organizzazione']
top_keywords = ", ".join(cluster_orgs.head(35)) # Prime 35 organizzazioni come rappresentanti
cluster_names.append(f"Cluster {cluster_id}: {top_keywords}")
colors = plt.cm.get_cmap("tab10", n_clusters).colors
plt.figure(figsize=(40, 40))
scatter_points = []
scatter_labels = []
for cluster_id in range(n_clusters):
cluster_mask = clusters == cluster_id
cluster_points = X_embedded[cluster_mask]
scatter = plt.scatter(
cluster_points[:, 0],
cluster_points[:, 1],
s=frequenze[cluster_mask] * 70,
c=[colors[cluster_id]],
alpha=0.7,
edgecolors='black'
)
scatter_points.append(scatter)
scatter_labels.append(cluster_names[cluster_id])
plt.title("\nRappresentazione delle prime 35 Organizzazioni con 20 cluster", fontsize=62)
plt.xlabel("\nt-SNE Dimension x", fontsize=52)
plt.ylabel("t-SNE Dimension y", fontsize=52)
plt.xticks(ha='right', fontsize=46, color='#b81414')
plt.yticks(ha='right', fontsize=46, color='#b81414')
plt.grid(True)
plt.tight_layout()
plt.show()
Rappresentazione delle prime 35 Organizzazioni con 20 cluster in 3D
Codice
orgs = df_organizations['Organizzazione'].values
frequenze = df_organizations['Frequenza'].values
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(orgs)
n_clusters = 20
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
clusters = kmeans.fit_predict(X)
tsne = TSNE(n_components=3, random_state=42)
X_embedded = tsne.fit_transform(X.toarray())
df_organizations['Cluster'] = clusters
cluster_names = []
for cluster_id in range(n_clusters):
cluster_orgs = df_organizations[df_organizations['Cluster'] == cluster_id].sort_values(by='Frequenza', ascending=False)['Organizzazione']
top_keywords = ", ".join(cluster_orgs.head(35)) # Prime 35 organizzazioni come rappresentanti
cluster_names.append(f"Cluster {cluster_id}: {top_keywords}")
colors = plt.cm.get_cmap("tab10", n_clusters).colors
fig = plt.figure(figsize=(40, 40))
ax = fig.add_subplot(111, projection='3d')
scatter_points = []
scatter_labels = []
# scatter 3D
for cluster_id in range(n_clusters):
cluster_mask = clusters == cluster_id
cluster_points = X_embedded[cluster_mask]
scatter = ax.scatter(
cluster_points[:, 0],
cluster_points[:, 1],
cluster_points[:, 2],
s=frequenze[cluster_mask] * 70,
c=[colors[cluster_id]],
alpha=0.7,
edgecolors='black'
)
scatter_points.append(scatter)
scatter_labels.append(cluster_names[cluster_id])
ax.set_title("\nRappresentazione delle prime 35 Organizzazioni con 20 cluster", fontsize=62)
ax.set_xlabel("t-SNE Dimension x", fontsize=52, labelpad=40)
ax.set_ylabel("t-SNE Dimension y", fontsize=52, labelpad=45)
ax.set_zlabel("t-SNE Dimension z", fontsize=52, labelpad=40)
ax.view_init(elev=30, azim=45)
ax.tick_params(axis='x', labelsize=46, colors='#b81414')
ax.tick_params(axis='y', labelsize=46, colors='#b81414')
ax.tick_params(axis='z', labelsize=46, colors='#b81414')
plt.grid(True)
plt.tight_layout()
plt.show()
Grafico 3D interattivo
Codice
import plotly.express as px
orgs = df_organizations['Organizzazione'].values
frequenze = df_organizations['Frequenza'].values
vectorizer = TfidfVectorizer()
X = vectorizer.fit_transform(orgs)
n_clusters = 20
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
clusters = kmeans.fit_predict(X)
tsne = TSNE(n_components=3, random_state=42, perplexity=10)
X_embedded = tsne.fit_transform(X.toarray())
df_organizations['Cluster'] = clusters
cluster_names = []
for cluster_id in range(n_clusters):
cluster_orgs = df_organizations[df_organizations['Cluster'] == cluster_id].sort_values(by='Frequenza', ascending=False)['Organizzazione']
top_keywords = ", ".join(cluster_orgs.head(35))
cluster_names.append(f"Cluster {cluster_id}: {top_keywords}")
colors = px.colors.qualitative.Set2
df_vis = pd.DataFrame(X_embedded, columns=['Dim1', 'Dim2', 'Dim3'])
df_vis['Organizzazione'] = orgs
df_vis['Frequenza'] = frequenze
df_vis['Cluster'] = clusters.astype(str) # Converto i cluster in stringa per la legenda
# Normalizzo le dimensioni per evitare valori troppo piccoli o nulli
df_vis['Frequenza'] = df_vis['Frequenza'].fillna(1) # Rimpiazza eventuali valori NaN con 1
df_vis['Size'] = df_vis['Frequenza'] * 20000000000000 # Scala della dimensione delle bolle
"""
Purtroppo le bolle sono sempre piccolissime
"""
# Grafico scatter 3D con Plotly
fig = px.scatter_3d(
df_vis,
x='Dim1',
y='Dim2',
z='Dim3',
color='Cluster', # Cluster come colori
size='Size', # Dimensioni proporzionali alla frequenza
hover_name='Organizzazione',
title="Rappresentazione delle prime 35 Organizzazioni con 20 cluster (3D)",
labels={'Dim1': 't-SNE Dimension x', 'Dim2': 't-SNE Dimension y', 'Dim3': 't-SNE Dimension z'},
color_discrete_sequence=colors
)
# Rimuovo il contorno nero e imposto colori pieni
fig.update_traces(marker=dict(line=dict(width=0)))
fig.update_layout(
width=1600,
height=1000,
legend_title="Cluster",
scene=dict(
xaxis_title="t-SNE Dimension x",
yaxis_title="t-SNE Dimension y",
zaxis_title="t-SNE Dimension z"
)
)
fig.show()
Grafico a bolle
Le dimensioni delle bolle rappresentano la frequenza delle organizzazioni.
Codice
import itertools
top_organizations = df_organizations.nlargest(35, 'Frequenza')
x = top_organizations['Organizzazione']
y = top_organizations['Frequenza']
sizes = top_organizations['Frequenza'] * 10 # Scala delle dimensioni delle bolle
colors = ['#0897B4', '#0B2B40', '#FF5F5D']
color_cycle = list(itertools.islice(itertools.cycle(colors), len(x)))
plt.figure(figsize=(12, 8))
plt.scatter(x, y, s=sizes, c=color_cycle, edgecolors='black', linewidth=0.3)
plt.xticks(
ticks=range(len(x)), # Indici delle etichette
labels=[f"{label}" for label in x], # Etichette
rotation=45,
ha='right', # Allineamento
fontsize=10,
color='black'
)
# Coloro individualmente le etichette
for i, tick_label in enumerate(plt.gca().get_xticklabels()):
tick_label.set_color(color_cycle[i]) # Colore corrispondente alla bolla
plt.title('\nRappresentazione delle prime 35 Organizzazioni', fontsize=18)
plt.xlabel('Organizzazioni', fontsize=16)
plt.ylabel('Frequenza', fontsize=16)
plt.yticks(fontsize=14, color='#b81414')
plt.tight_layout()
plt.show()
Costruzione e addestramento di un classificatore per la rilevazione di email SPAM
Analisi del dataset
Breve recap sul dataset raw iniziale
Codice
df_email.head()
Out[34]:
| Unnamed: 0 | label | text | label_num | |
|---|---|---|---|---|
| 0 | 605 | ham | Subject: enron methanol ; meter # : 988291\nth... | 0 |
| 1 | 2349 | ham | Subject: hpl nom for january 9 , 2001\n( see a... | 0 |
| 2 | 3624 | ham | Subject: neon retreat\nho ho ho , we ' re arou... | 0 |
| 3 | 4685 | spam | Subject: photoshop , windows , office . cheap ... | 1 |
| 4 | 2030 | ham | Subject: re : indian springs\nthis deal is to ... | 0 |
Codice
# Calcolo del peso totale del dataset in memoria
df_email_size = df_email.memory_usage(deep=True).sum()
# Conversione in megabyte (MB)
df_email_size_mb = df_email_size / (1024 ** 2)
print_colored(f"Il peso del dataset raw in memoria è di:", "blue")
print(f"{df_email_size_mb:.2f} MB")
Il peso del dataset raw in memoria è di:
5.66 MB
Codice
df_email_dropped = df_email.drop(columns=['Unnamed: 0', 'label'])
print_colored("Dataset df_email dropped\n", "blue")
print(df_email_dropped.head())
Dataset df_email dropped
text label_num
0 Subject: enron methanol ; meter # : 988291\nth... 0
1 Subject: hpl nom for january 9 , 2001\n( see a... 0
2 Subject: neon retreat\nho ho ho , we ' re arou... 0
3 Subject: photoshop , windows , office . cheap ... 1
4 Subject: re : indian springs\nthis deal is to ... 0
Codice
label_count.plot(kind='bar', figsize=(10, 6))
plt.title("\nDistribuzione di ham e spam", fontsize=18)
plt.xlabel("Label (0 = ham, 1 = spam)", fontsize=14)
plt.ylabel("Conteggio", fontsize=14)
plt.xticks(fontsize=12, color='#b81414', rotation=0)
plt.yticks(fontsize=12, color='#b81414')
plt.grid(axis='y', linestyle='--', alpha=0.5, color="#1f77b4")
plt.show()
Preprocessing del testo delle email HAM e SPAM
Faccio il preprocessing prima del bilanciamento del dataset per evitare di duplicare dati sporchi, per avere una migliore qualità dei dati e per ridurre i calcoli computazionali
Codice
# Inizializzo stopwords e lemmatizer
stop_words = set(stopwords.words('english')) # Stopword per la lingua inglese
# Rimuove parole comuni inglesi per ridurre il rumore nei dati
lemmatizer = WordNetLemmatizer() # Riduce le parole alla loro forma base per
# diminuire la dimensionalità del vocabolario
def clean_text(text):
# Rimuovo caratteri speciali e punteggiatura
text = re.sub(r'[^a-zA-Z\s]', '', text)
# Converto tutte le lettere in minuscolo
text = text.lower()
# Rimuovo la parola 'subject' se presente perché si riferisce alla struttura standard di un'email
# non aggiunge valore informativo per l'analisi, anzi, può influenzarla negativamente
text = text.replace('subject', '')
tokens = [lemmatizer.lemmatize(word, pos='v') for word in text.split() if word not in stop_words]
return ' '.join(tokens)
# Creo la colonna cleaned_text e applico la pulizia del testo
df_email_dropped['cleaned_text'] = df_email_dropped['text'].apply(clean_text)
print_colored("Colonna 'text' originale", "blue")
print(df_email_dropped[['text']].head())
print()
print_colored("Colonna 'clean_text' con l'applicazione della funzione 'clean_text' alla colonna 'text'", "blue")
print(df_email_dropped[['cleaned_text']].head())
Colonna 'text' originale text 0 Subject: enron methanol ; meter # : 988291\nth... 1 Subject: hpl nom for january 9 , 2001\n( see a... 2 Subject: neon retreat\nho ho ho , we ' re arou... 3 Subject: photoshop , windows , office . cheap ... 4 Subject: re : indian springs\nthis deal is to ... Colonna 'clean_text' con l'applicazione della funzione 'clean_text' alla colonna 'text' cleaned_text 0 enron methanol meter follow note give monday p... 1 hpl nom january see attach file hplnol xls hpl... 2 neon retreat ho ho ho around wonderful time ye... 3 photoshop windows office cheap main trend abas... 4 indian spring deal book teco pvr revenue under...
Codice
df_email_dropped.head()
Out[39]:
| text | label_num | cleaned_text | |
|---|---|---|---|
| 0 | Subject: enron methanol ; meter # : 988291\nth... | 0 | enron methanol meter follow note give monday p... |
| 1 | Subject: hpl nom for january 9 , 2001\n( see a... | 0 | hpl nom january see attach file hplnol xls hpl... |
| 2 | Subject: neon retreat\nho ho ho , we ' re arou... | 0 | neon retreat ho ho ho around wonderful time ye... |
| 3 | Subject: photoshop , windows , office . cheap ... | 1 | photoshop windows office cheap main trend abas... |
| 4 | Subject: re : indian springs\nthis deal is to ... | 0 | indian spring deal book teco pvr revenue under... |
Codice
# Calcolo del peso totale del dataset in memoria
df_email_dropped_size = df_email_dropped.memory_usage(deep=True).sum()
# Conversione in megabyte (MB)
df_email_dropped_mb = df_email_dropped_size / (1024 ** 2)
print_colored(f"Il peso del dataset 'df_email_dropped' in memoria è di:", "blue")
print(f"{df_email_dropped_mb:.2f} MB")
Il peso del dataset 'df_email_dropped' in memoria è di:
8.68 MB
Codice
df_email_dropped_cleaned = df_email_dropped.drop(columns=['text'])
print_colored("Dataset 'df_email_dropped' cleaned\n", "blue")
print(df_email_dropped_cleaned.head())
Dataset 'df_email_dropped' cleaned
label_num cleaned_text
0 0 enron methanol meter follow note give monday p...
1 0 hpl nom january see attach file hplnol xls hpl...
2 0 neon retreat ho ho ho around wonderful time ye...
3 1 photoshop windows office cheap main trend abas...
4 0 indian spring deal book teco pvr revenue under...
Codice
# Calcolo del peso totale del dataset in memoria
df_email_dropped_cleaned_size = df_email_dropped_cleaned.memory_usage(deep=True).sum()
# Conversione in megabyte (MB)
df_email_dropped_cleaned_mb = df_email_dropped_cleaned_size / (1024 ** 2)
print_colored(f"Il peso del dataset raw in memoria è di:", "blue")
print(f"{df_email_dropped_cleaned_mb:.2f} MB")
Il peso del dataset raw in memoria è di:
3.36 MB
Codice
dataset_size_difference = df_email_size_mb - df_email_dropped_cleaned_mb
print_colored(f"La memoria liberata grazie al dropout e alla pulizia del testo rispetto al dataset di partenza è di:", "blue")
print(f"{dataset_size_difference:.2f} MB")
total_size = df_email_size_mb + df_email_dropped_cleaned_mb
difference_percentage_size = (dataset_size_difference/total_size)*100
print_colored(f"Percentuale di memoria liberata:", "blue")
print(f"{difference_percentage_size:.2f} %")
La memoria liberata grazie al dropout e alla pulizia del testo rispetto al dataset di partenza è di: 2.30 MB Percentuale di memoria liberata: 25.54 %
Implemento il bilanciamento delle classi con SMOTE
Codice
from imblearn.over_sampling import SMOTE
# Estraggo feature e label
X = df_email_dropped_cleaned['cleaned_text']
y = df_email_dropped_cleaned['label_num']
# Conversione del testo in rappresentazione numerica TF-IDF
vectorizer = TfidfVectorizer(max_features=5000) # Limito il numero di feature per evitare sovraccarico di memoria
X_tfidf = vectorizer.fit_transform(X)
# Converto in DataFrame se necessario
if not isinstance(X_tfidf, pd.DataFrame):
X_tfidf = pd.DataFrame(X_tfidf.toarray(), columns=[f'feature_{i}' for i in range(X_tfidf.shape[1])])
if not isinstance(y, pd.DataFrame):
y = pd.DataFrame(y, columns=['label_num'])
# Applico SMOTE per bilanciare le classi
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X_tfidf, y)
# Converto i dati bilanciati in DataFrame per facilitarne l'uso successivo
df_balanced = pd.concat([pd.DataFrame(X_resampled, columns=X_tfidf.columns), pd.DataFrame(y_resampled, columns=['label_num'])], axis=1)
print_colored("Distribuzione delle classi dopo SMOTE:", "blue")
print(Counter(y_resampled['label_num']))
Distribuzione delle classi dopo SMOTE:
Counter({0: 3672, 1: 3672})
Codice
label_counts = df_balanced['label_num'].value_counts()
df_plot = pd.DataFrame({
'Categoria': ['Ham', 'Spam'],
'Conteggio': [label_counts.get(0, 0), label_counts.get(1, 0)]
})
plt.figure(figsize=(10, 6))
plt.bar(df_plot['Categoria'], df_plot['Conteggio'], color=['#1f77b4', '#ff7f0e'])
plt.title("\nDistribuzione di ham e spam", fontsize=18)
plt.xlabel("Categoria", fontsize=14)
plt.ylabel("Conteggio", fontsize=14)
plt.xticks(fontsize=12, color='#b81414', rotation=0)
plt.yticks(fontsize=12, color='#b81414')
plt.grid(axis='y', linestyle='--', alpha=0.5, color="#1f77b4")
plt.show()
Creazione dei classificatori
Codice
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, Conv1D, MaxPooling1D, LSTM, GRU, Dense, Dropout, Bidirectional, Flatten
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
from tensorflow.keras.preprocessing.text import Tokenizer
# Suddivisione del dataset in train, validation e test (70-15-15) con stratificazione
X = df_email_dropped_cleaned['cleaned_text'].values # Testi puliti
y = df_email_dropped_cleaned['label_num'].values # Etichette spam/ham
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.30, stratify=y, random_state=42)
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.50, stratify=y_temp, random_state=42)
print_colored(f"Training set:", "blue")
print(len(X_train))
print_colored(f"\nVal set:", "blue")
print(len(X_val))
print_colored(f"\nTest set:", "blue")
print(len(X_test))
Training set: 3619 Val set: 776 Test set: 776
Codice
# Conversione dei dati per l'uso con reti neurali (TensorFlow)
X_train_tfidf = tf.convert_to_tensor(X_train_tfidf, dtype=tf.float32)
X_val_tfidf = tf.convert_to_tensor(X_val_tfidf, dtype=tf.float32)
X_test_tfidf = tf.convert_to_tensor(X_test_tfidf, dtype=tf.float32)
y_train = tf.convert_to_tensor(y_train, dtype=tf.float32)
y_val = tf.convert_to_tensor(y_val, dtype=tf.float32)
y_test = tf.convert_to_tensor(y_test, dtype=tf.float32)
Codice
# Verifico la dimensione dei dati
print("Shape X_train:", X_train_tfidf.shape, "Y_train:", y_train.shape)
print("Shape X_val:", X_val_tfidf.shape, "Y_val:", y_val.shape)
print("Shape X_test:", X_test_tfidf.shape, "Y_test:", y_test.shape)
import joblib
joblib.dump(vectorizer, 'classificatori/MLP/tfidf_vectorizer.pkl')
Shape X_train: (3619, 3500) Y_train: (3619,) Shape X_val: (776, 3500) Y_val: (776,) Shape X_test: (776, 3500) Y_test: (776,)
Out[50]:
['classificatori/MLP/tfidf_vectorizer.pkl']
Modello MLP
Codice
model_name = "MLP"
print(model_name)
MLP
Codice
# Callbacks per il monitoraggio
callbacks = [
EarlyStopping(
monitor='val_loss',
patience=10,
restore_best_weights=True,
mode='min',
min_delta=0.001
),
ReduceLROnPlateau(
monitor='val_loss',
factor=0.5,
patience=5,
min_lr=1e-6,
verbose=1,
),
ModelCheckpoint(
f"classificatori/MLP/{model_name}_best_model.keras",
monitor='val_loss',
save_best_only=True,
verbose=1
)
]
Codice
from tensorflow.keras.regularizers import l1, l2
mlp_model = Sequential([
Dense(256, activation='relu', input_shape=(X_train_tfidf.shape[1],),
kernel_regularizer=l2(0.001)),
Dropout(0.3),
Dense(128, activation='relu',
kernel_regularizer=l2(0.001)),
Dropout(0.3),
Dense(64, activation='relu',
kernel_regularizer=l2(0.001)),
Dense(1, activation='sigmoid')
])
Codice
mlp_model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.0005),
loss='binary_crossentropy',
metrics=['accuracy'])
mlp_model.summary()
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ dense (Dense) │ (None, 256) │ 896,256 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout (Dropout) │ (None, 256) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_1 (Dense) │ (None, 128) │ 32,896 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_1 (Dropout) │ (None, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_2 (Dense) │ (None, 64) │ 8,256 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_3 (Dense) │ (None, 1) │ 65 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 937,473 (3.58 MB)
Trainable params: 937,473 (3.58 MB)
Non-trainable params: 0 (0.00 B)
Codice
history_mlp = mlp_model.fit(
X_train_tfidf, y_train,
validation_data=(X_val_tfidf, y_val),
epochs=50,
batch_size=32,
callbacks=callbacks
)
Epoch 1/50
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR I0000 00:00:1737558883.542210 19651 service.cc:148] XLA service 0x7bce2c01d180 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices: I0000 00:00:1737558883.542229 19651 service.cc:156] StreamExecutor device (0): NVIDIA GeForce RTX 4070 Laptop GPU, Compute Capability 8.9 I0000 00:00:1737558883.650929 19651 cuda_dnn.cc:529] Loaded cuDNN version 90600
79/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.6899 - loss: 1.1224
I0000 00:00:1737558884.286870 19651 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.
114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 10ms/step - accuracy: 0.7182 - loss: 1.0206 Epoch 1: val_loss improved from inf to 0.31479, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 4s 25ms/step - accuracy: 0.7190 - loss: 1.0180 - val_accuracy: 0.9704 - val_loss: 0.3148 - learning_rate: 5.0000e-04 Epoch 2/50 103/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9890 - loss: 0.2398 Epoch 2: val_loss improved from 0.31479 to 0.18427, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9888 - loss: 0.2373 - val_accuracy: 0.9832 - val_loss: 0.1843 - learning_rate: 5.0000e-04 Epoch 3/50 81/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9984 - loss: 0.1453 Epoch 3: val_loss improved from 0.18427 to 0.15297, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9982 - loss: 0.1429 - val_accuracy: 0.9820 - val_loss: 0.1530 - learning_rate: 5.0000e-04 Epoch 4/50 111/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9984 - loss: 0.1050 Epoch 4: val_loss improved from 0.15297 to 0.12904, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9984 - loss: 0.1049 - val_accuracy: 0.9768 - val_loss: 0.1290 - learning_rate: 5.0000e-04 Epoch 5/50 79/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9995 - loss: 0.0915 Epoch 5: val_loss improved from 0.12904 to 0.11600, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9993 - loss: 0.0904 - val_accuracy: 0.9807 - val_loss: 0.1160 - learning_rate: 5.0000e-04 Epoch 6/50 82/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9995 - loss: 0.0763 Epoch 6: val_loss improved from 0.11600 to 0.10993, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9994 - loss: 0.0759 - val_accuracy: 0.9781 - val_loss: 0.1099 - learning_rate: 5.0000e-04 Epoch 7/50 100/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9982 - loss: 0.0691 Epoch 7: val_loss improved from 0.10993 to 0.10971, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9983 - loss: 0.0692 - val_accuracy: 0.9794 - val_loss: 0.1097 - learning_rate: 5.0000e-04 Epoch 8/50 81/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9985 - loss: 0.0677 Epoch 8: val_loss improved from 0.10971 to 0.10902, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9985 - loss: 0.0676 - val_accuracy: 0.9781 - val_loss: 0.1090 - learning_rate: 5.0000e-04 Epoch 9/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9999 - loss: 0.0576 Epoch 9: val_loss improved from 0.10902 to 0.09849, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9999 - loss: 0.0576 - val_accuracy: 0.9794 - val_loss: 0.0985 - learning_rate: 5.0000e-04 Epoch 10/50 83/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 1.0000 - loss: 0.0541 Epoch 10: val_loss did not improve from 0.09849 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 1.0000 - loss: 0.0541 - val_accuracy: 0.9742 - val_loss: 0.1081 - learning_rate: 5.0000e-04 Epoch 11/50 107/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9990 - loss: 0.0551 Epoch 11: val_loss did not improve from 0.09849 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.9990 - loss: 0.0552 - val_accuracy: 0.9742 - val_loss: 0.1010 - learning_rate: 5.0000e-04 Epoch 12/50 82/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9991 - loss: 0.0517 Epoch 12: val_loss did not improve from 0.09849 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9989 - loss: 0.0527 - val_accuracy: 0.9807 - val_loss: 0.1046 - learning_rate: 5.0000e-04 Epoch 13/50 102/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9999 - loss: 0.0559 Epoch 13: val_loss improved from 0.09849 to 0.09842, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9998 - loss: 0.0560 - val_accuracy: 0.9794 - val_loss: 0.0984 - learning_rate: 5.0000e-04 Epoch 14/50 102/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9993 - loss: 0.0530 Epoch 14: val_loss improved from 0.09842 to 0.08891, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9994 - loss: 0.0528 - val_accuracy: 0.9820 - val_loss: 0.0889 - learning_rate: 5.0000e-04 Epoch 15/50 78/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 1.0000 - loss: 0.0523 Epoch 15: val_loss did not improve from 0.08891 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9995 - loss: 0.0535 - val_accuracy: 0.9768 - val_loss: 0.1134 - learning_rate: 5.0000e-04 Epoch 16/50 80/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9984 - loss: 0.0552 Epoch 16: val_loss did not improve from 0.08891 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9986 - loss: 0.0550 - val_accuracy: 0.9755 - val_loss: 0.1108 - learning_rate: 5.0000e-04 Epoch 17/50 78/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9985 - loss: 0.0515 Epoch 17: val_loss did not improve from 0.08891 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9984 - loss: 0.0519 - val_accuracy: 0.9781 - val_loss: 0.1012 - learning_rate: 5.0000e-04 Epoch 18/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 1.0000 - loss: 0.0485 Epoch 18: val_loss did not improve from 0.08891 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 1.0000 - loss: 0.0485 - val_accuracy: 0.9755 - val_loss: 0.1028 - learning_rate: 5.0000e-04 Epoch 19/50 110/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 1.0000 - loss: 0.0445 Epoch 19: val_loss improved from 0.08891 to 0.08301, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9999 - loss: 0.0445 - val_accuracy: 0.9845 - val_loss: 0.0830 - learning_rate: 5.0000e-04 Epoch 20/50 105/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9990 - loss: 0.0439 Epoch 20: val_loss did not improve from 0.08301 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9990 - loss: 0.0439 - val_accuracy: 0.9820 - val_loss: 0.0895 - learning_rate: 5.0000e-04 Epoch 21/50 78/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9993 - loss: 0.0435 Epoch 21: val_loss did not improve from 0.08301 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9992 - loss: 0.0439 - val_accuracy: 0.9768 - val_loss: 0.0895 - learning_rate: 5.0000e-04 Epoch 22/50 100/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9997 - loss: 0.0425 Epoch 22: val_loss did not improve from 0.08301 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9997 - loss: 0.0426 - val_accuracy: 0.9820 - val_loss: 0.0842 - learning_rate: 5.0000e-04 Epoch 23/50 107/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9999 - loss: 0.0400 Epoch 23: val_loss did not improve from 0.08301 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9998 - loss: 0.0401 - val_accuracy: 0.9794 - val_loss: 0.0877 - learning_rate: 5.0000e-04 Epoch 24/50 80/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9997 - loss: 0.0407 Epoch 24: ReduceLROnPlateau reducing learning rate to 0.0002500000118743628. Epoch 24: val_loss did not improve from 0.08301 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9994 - loss: 0.0415 - val_accuracy: 0.9832 - val_loss: 0.0905 - learning_rate: 5.0000e-04 Epoch 25/50 110/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9997 - loss: 0.0424 Epoch 25: val_loss improved from 0.08301 to 0.08101, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9997 - loss: 0.0424 - val_accuracy: 0.9820 - val_loss: 0.0810 - learning_rate: 2.5000e-04 Epoch 26/50 79/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9984 - loss: 0.0398 Epoch 26: val_loss did not improve from 0.08101 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9987 - loss: 0.0391 - val_accuracy: 0.9794 - val_loss: 0.0812 - learning_rate: 2.5000e-04 Epoch 27/50 82/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9998 - loss: 0.0346 Epoch 27: val_loss improved from 0.08101 to 0.07993, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9998 - loss: 0.0349 - val_accuracy: 0.9794 - val_loss: 0.0799 - learning_rate: 2.5000e-04 Epoch 28/50 78/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9995 - loss: 0.0348 Epoch 28: val_loss improved from 0.07993 to 0.07549, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9995 - loss: 0.0347 - val_accuracy: 0.9832 - val_loss: 0.0755 - learning_rate: 2.5000e-04 Epoch 29/50 110/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9996 - loss: 0.0341 Epoch 29: val_loss did not improve from 0.07549 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9996 - loss: 0.0341 - val_accuracy: 0.9781 - val_loss: 0.0863 - learning_rate: 2.5000e-04 Epoch 30/50 110/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9996 - loss: 0.0342 Epoch 30: val_loss did not improve from 0.07549 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9996 - loss: 0.0342 - val_accuracy: 0.9820 - val_loss: 0.0759 - learning_rate: 2.5000e-04 Epoch 31/50 110/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 1.0000 - loss: 0.0315 Epoch 31: val_loss did not improve from 0.07549 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9999 - loss: 0.0316 - val_accuracy: 0.9832 - val_loss: 0.0768 - learning_rate: 2.5000e-04 Epoch 32/50 80/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9991 - loss: 0.0345 Epoch 32: val_loss did not improve from 0.07549 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9993 - loss: 0.0341 - val_accuracy: 0.9820 - val_loss: 0.0760 - learning_rate: 2.5000e-04 Epoch 33/50 81/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9997 - loss: 0.0325 Epoch 33: ReduceLROnPlateau reducing learning rate to 0.0001250000059371814. Epoch 33: val_loss did not improve from 0.07549 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9997 - loss: 0.0324 - val_accuracy: 0.9781 - val_loss: 0.0804 - learning_rate: 2.5000e-04 Epoch 34/50 79/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 1.0000 - loss: 0.0298 Epoch 34: val_loss did not improve from 0.07549 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 1.0000 - loss: 0.0301 - val_accuracy: 0.9807 - val_loss: 0.0792 - learning_rate: 1.2500e-04 Epoch 35/50 79/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9996 - loss: 0.0318 Epoch 35: val_loss did not improve from 0.07549 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9996 - loss: 0.0317 - val_accuracy: 0.9807 - val_loss: 0.0784 - learning_rate: 1.2500e-04 Epoch 36/50 98/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 1.0000 - loss: 0.0295 Epoch 36: val_loss improved from 0.07549 to 0.07423, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 1.0000 - loss: 0.0296 - val_accuracy: 0.9820 - val_loss: 0.0742 - learning_rate: 1.2500e-04 Epoch 37/50 80/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 1.0000 - loss: 0.0307 Epoch 37: val_loss did not improve from 0.07423 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 1.0000 - loss: 0.0306 - val_accuracy: 0.9768 - val_loss: 0.0755 - learning_rate: 1.2500e-04 Epoch 38/50 80/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9989 - loss: 0.0312 Epoch 38: val_loss did not improve from 0.07423 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9991 - loss: 0.0308 - val_accuracy: 0.9807 - val_loss: 0.0749 - learning_rate: 1.2500e-04 Epoch 39/50 111/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9995 - loss: 0.0295 Epoch 39: val_loss did not improve from 0.07423 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9995 - loss: 0.0295 - val_accuracy: 0.9781 - val_loss: 0.0776 - learning_rate: 1.2500e-04 Epoch 40/50 77/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9999 - loss: 0.0287 Epoch 40: val_loss did not improve from 0.07423 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9998 - loss: 0.0289 - val_accuracy: 0.9755 - val_loss: 0.0815 - learning_rate: 1.2500e-04 Epoch 41/50 82/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9990 - loss: 0.0327 Epoch 41: ReduceLROnPlateau reducing learning rate to 6.25000029685907e-05. Epoch 41: val_loss did not improve from 0.07423 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9992 - loss: 0.0320 - val_accuracy: 0.9781 - val_loss: 0.0767 - learning_rate: 1.2500e-04 Epoch 42/50 79/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 1.0000 - loss: 0.0282 Epoch 42: val_loss did not improve from 0.07423 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9999 - loss: 0.0286 - val_accuracy: 0.9807 - val_loss: 0.0749 - learning_rate: 6.2500e-05 Epoch 43/50 105/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9999 - loss: 0.0283 Epoch 43: val_loss improved from 0.07423 to 0.07366, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9999 - loss: 0.0284 - val_accuracy: 0.9807 - val_loss: 0.0737 - learning_rate: 6.2500e-05 Epoch 44/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 1.0000 - loss: 0.0280 Epoch 44: val_loss did not improve from 0.07366 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 1.0000 - loss: 0.0280 - val_accuracy: 0.9807 - val_loss: 0.0742 - learning_rate: 6.2500e-05 Epoch 45/50 79/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9995 - loss: 0.0288 Epoch 45: val_loss improved from 0.07366 to 0.07352, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9996 - loss: 0.0288 - val_accuracy: 0.9807 - val_loss: 0.0735 - learning_rate: 6.2500e-05 Epoch 46/50 84/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9996 - loss: 0.0289 Epoch 46: val_loss improved from 0.07352 to 0.07270, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9996 - loss: 0.0288 - val_accuracy: 0.9807 - val_loss: 0.0727 - learning_rate: 6.2500e-05 Epoch 47/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9998 - loss: 0.0282 Epoch 47: val_loss improved from 0.07270 to 0.07252, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9998 - loss: 0.0282 - val_accuracy: 0.9820 - val_loss: 0.0725 - learning_rate: 6.2500e-05 Epoch 48/50 103/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9997 - loss: 0.0282 Epoch 48: val_loss did not improve from 0.07252 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9997 - loss: 0.0282 - val_accuracy: 0.9781 - val_loss: 0.0742 - learning_rate: 6.2500e-05 Epoch 49/50 80/114 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9997 - loss: 0.0281 Epoch 49: val_loss improved from 0.07252 to 0.07171, saving model to classificatori/MLP/MLP_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9997 - loss: 0.0282 - val_accuracy: 0.9832 - val_loss: 0.0717 - learning_rate: 6.2500e-05 Epoch 50/50 91/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9997 - loss: 0.0278 Epoch 50: val_loss did not improve from 0.07171 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 2ms/step - accuracy: 0.9997 - loss: 0.0279 - val_accuracy: 0.9781 - val_loss: 0.0736 - learning_rate: 6.2500e-05
Valutazione del modello MLP sul test set
Codice
from sklearn.metrics import classification_report, confusion_matrix
best_model = tf.keras.models.load_model(f"classificatori/MLP/{model_name}_best_model.keras")
test_scores = best_model.evaluate(X_test_tfidf, y_test, verbose=1)
print_colored(f"\nTest loss: MLP", "blue")
test_loss_score_mlp = f"{test_scores[0]:.4f}"
print(test_loss_score_mlp)
print_colored(f"\nTest accuracy: MLP", "blue")
test_accuracy_score_mlp = f"{test_scores[1]:.4f}"
print(test_accuracy_score_mlp)
y_pred = best_model.predict(X_test_tfidf)
y_pred_classes = (y_pred > 0.5).astype(int)
print_colored('\nClassification Report MLP:', "blue")
classification_report_mlp = classification_report(y_test, y_pred_classes)
print(classification_report_mlp)
print_colored('\nConfusion Matrix MLP:', "blue")
confusion_matrix_mlp = confusion_matrix(y_test, y_pred_classes)
print(confusion_matrix_mlp)
25/25 ━━━━━━━━━━━━━━━━━━━━ 1s 9ms/step - accuracy: 0.9826 - loss: 0.0755 Test loss: MLP 0.0902 Test accuracy: MLP 0.9794 25/25 ━━━━━━━━━━━━━━━━━━━━ 0s 8ms/step Classification Report MLP: precision recall f1-score support 0.0 0.98 0.99 0.99 551 1.0 0.97 0.96 0.96 225 accuracy 0.98 776 macro avg 0.98 0.97 0.97 776 weighted avg 0.98 0.98 0.98 776 Confusion Matrix MLP: [[544 7] [ 9 216]]
Codice
print(f"File caricato: classificatori/MLP/{model_name}_best_model.keras")
File caricato: classificatori/MLP/MLP_best_model.keras
Previsioni del modello
Codice
num_examples = 15
for idx in range(num_examples):
email_vector = X_test_tfidf[idx] # Vettore TF-IDF dell'email
true_label = int(y_test[idx]) # Etichetta vera (convertita a int)
predicted_prob = y_pred[idx] # Probabilità predette (array)
predicted_label = int(y_pred_classes[idx]) # Etichetta predetta (convertita a int)
prob_value = predicted_prob[0] if predicted_prob.ndim > 0 else predicted_prob
match = "✅" if predicted_label == true_label else "❌"
print_colored(f"Email N.{idx + 1}:", "blue")
print(f" - Predetta: {predicted_label} (Probabilità: {prob_value:.2f}) {match}")
print(f" - Vera: {true_label}")
Email N.1: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 Email N.2: - Predetta: 1 (Probabilità: 0.98) ✅ - Vera: 1 Email N.3: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 Email N.4: - Predetta: 0 (Probabilità: 0.01) ✅ - Vera: 0 Email N.5: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 Email N.6: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 Email N.7: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 Email N.8: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 Email N.9: - Predetta: 0 (Probabilità: 0.27) ✅ - Vera: 0 Email N.10: - Predetta: 1 (Probabilità: 1.00) ✅ - Vera: 1 Email N.11: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 Email N.12: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 Email N.13: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 Email N.14: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 Email N.15: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0
Codice
print(y_pred[:15]) # Mostro le prime probabilità predette
[[1.2562265e-04] [9.8261309e-01] [1.1322779e-04] [8.3334576e-03] [1.6125961e-03] [3.5835081e-05] [3.7307975e-05] [9.0621259e-05] [2.6709902e-01] [9.9749810e-01] [5.7599609e-05] [1.9880630e-04] [1.7158085e-04] [9.9053039e-05] [2.6507804e-03]]
Codice
plt.hist(y_pred, bins=20, edgecolor="black")
plt.title("Distribuzione delle probabilità predette")
plt.xlabel("Probabilità")
plt.ylabel("Frequenza")
plt.show()
Codice
print(X_test[idx]) # Visualizzo il contenuto dell'email
cornhusker contract information rick attach complete letter party request note two letter lone star two letter apache since send electronically michael mazowita obtain signature rick vicens please copy execute letter send sandi braband attention letter print appropriate letterhead copy send cc bottom letter question please let know bob walker sr legal specialist
Modello CNN
Analisi della lunghezza e frequenza delle parole per l'ottimizzazione del modello NLP
Codice
email_lengths = [len(text.split()) for text in X] # X è la lista delle email
print("Lunghezza media:", np.mean(email_lengths))
print("Lunghezza massima:", np.max(email_lengths))
print("90° percentile:", np.percentile(email_lengths, 90))
Lunghezza media: 95.79965190485399 Lunghezza massima: 3336 90° percentile: 227.0
Codice
all_words = ' '.join(X).split()
word_freq = Counter(all_words)
sorted_word_freq = sorted(word_freq.values(), reverse=True)
cumulative_freq = [sum(sorted_word_freq[:i]) for i in range(1, len(sorted_word_freq))]
print("Cumulative frequency")
print(len(cumulative_freq))
plt.plot(range(len(cumulative_freq)), cumulative_freq)
plt.xlabel('Numero di parole')
plt.ylabel('Frequenza cumulativa')
plt.title('Distribuzione della frequenza delle parole')
plt.show()
Cumulative frequency 42056
Codice
spam_emails = df_email_dropped_cleaned[df_email_dropped_cleaned['label_num'] == 1]['cleaned_text']
ham_emails = df_email_dropped_cleaned[df_email_dropped_cleaned['label_num'] == 0]['cleaned_text']
print("Parole uniche nelle email di spam:", len(set(' '.join(spam_emails).split())))
print("Parole uniche nelle email ham:", len(set(' '.join(ham_emails).split())))
Parole uniche nelle email di spam: 34611 Parole uniche nelle email ham: 13920
Codice
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Embedding, Conv1D, MaxPooling1D, Flatten, Dense, Dropout
Codice
# Tokenizzazione del testo per CNN
max_vocab_size = 10000 # Numero massimo di parole nel vocabolario
max_sequence_length = 200 # Lunghezza massima delle sequenze
tokenizer = Tokenizer(num_words=max_vocab_size, oov_token="<OOV>")
tokenizer.fit_on_texts(X_train)
Codice
# Converto i testi in sequenze di interi
X_train_seq = tokenizer.texts_to_sequences(X_train)
X_val_seq = tokenizer.texts_to_sequences(X_val)
X_test_seq = tokenizer.texts_to_sequences(X_test)
Codice
# Padding delle sequenze per avere lunghezza uniforme
X_train_pad = pad_sequences(X_train_seq, maxlen=max_sequence_length, padding='post', truncating='post')
X_val_pad = pad_sequences(X_val_seq, maxlen=max_sequence_length, padding='post', truncating='post')
X_test_pad = pad_sequences(X_test_seq, maxlen=max_sequence_length, padding='post', truncating='post')
Codice
# Conversione delle etichette in tensori
y_train = tf.convert_to_tensor(y_train, dtype=tf.float32)
y_val = tf.convert_to_tensor(y_val, dtype=tf.float32)
y_test = tf.convert_to_tensor(y_test, dtype=tf.float32)
Codice
print_colored("Shape X_train:", "blue")
print(X_train_pad.shape, "Y_train:", y_train.shape)
print_colored("\nShape X_val:", "blue")
print(X_val_pad.shape, "Y_val:", y_val.shape)
print_colored("\nShape X_test:", "blue")
print(X_test_pad.shape, "Y_test:", y_test.shape)
Shape X_train: (3619, 200) Y_train: (3619,) Shape X_val: (776, 200) Y_val: (776,) Shape X_test: (776, 200) Y_test: (776,)
Codice
joblib.dump(tokenizer, 'classificatori/cnn_tokenizer.pkl')
Out[115]:
['classificatori/cnn_tokenizer.pkl']
Codice
from tensorflow.keras.layers import BatchNormalization
cnn_model = Sequential([
Embedding(input_dim=max_vocab_size,
output_dim=128,
input_length=max_sequence_length,
embeddings_regularizer=l2(0.001)), # Regolarizzazione L2 sull'embedding
Conv1D(filters=128,
kernel_size=5,
activation='relu',
kernel_regularizer=l2(0.001)), # Regolarizzazione L2
BatchNormalization(), # Batch Normalization
MaxPooling1D(pool_size=2),
Conv1D(filters=64,
kernel_size=3,
activation='relu',
kernel_regularizer=l2(0.001)), # Regolarizzazione L2
BatchNormalization(), # Batch Normalization
MaxPooling1D(pool_size=2),
Flatten(),
Dense(64,
activation='relu',
kernel_regularizer=l2(0.001)), # Regolarizzazione L2
BatchNormalization(),
Dropout(0.5),
Dense(1, activation='sigmoid')
])
Codice
cnn_model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.0005),
loss='binary_crossentropy',
metrics=['accuracy'])
Codice
cnn_model.summary()
Model: "sequential_9"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ embedding_3 (Embedding) │ ? │ 0 (unbuilt) │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv1d_5 (Conv1D) │ ? │ 0 (unbuilt) │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ batch_normalization │ ? │ 0 (unbuilt) │ │ (BatchNormalization) │ │ │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling1d_4 (MaxPooling1D) │ ? │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv1d_6 (Conv1D) │ ? │ 0 (unbuilt) │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ batch_normalization_1 │ ? │ 0 (unbuilt) │ │ (BatchNormalization) │ │ │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling1d_5 (MaxPooling1D) │ ? │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ flatten_2 (Flatten) │ ? │ 0 (unbuilt) │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_29 (Dense) │ ? │ 0 (unbuilt) │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ batch_normalization_2 │ ? │ 0 (unbuilt) │ │ (BatchNormalization) │ │ │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_17 (Dropout) │ ? │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_30 (Dense) │ ? │ 0 (unbuilt) │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 0 (0.00 B)
Trainable params: 0 (0.00 B)
Non-trainable params: 0 (0.00 B)
Codice
model_name = "CNN"
print(model_name)
CNN
Codice
callbacks = [
EarlyStopping(
monitor='val_loss',
patience=7,
restore_best_weights=True,
mode='min'
),
ReduceLROnPlateau(
monitor='val_loss',
factor=0.5,
patience=4,
min_lr=1e-6,
verbose=1
),
ModelCheckpoint(
f"classificatori/{model_name}_best_model.keras",
monitor='val_loss',
save_best_only=True,
verbose=1
)
]
Codice
history_cnn = cnn_model.fit(
X_train_pad, y_train,
validation_data=(X_val_pad, y_val),
epochs=50,
batch_size=32,
callbacks=callbacks
)
Epoch 1/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 16ms/step - accuracy: 0.6870 - loss: 1.8070 Epoch 1: val_loss improved from inf to 1.43671, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 3s 18ms/step - accuracy: 0.6888 - loss: 1.8013 - val_accuracy: 0.8222 - val_loss: 1.4367 - learning_rate: 5.0000e-04 Epoch 2/50 112/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9365 - loss: 1.0147 Epoch 2: val_loss improved from 1.43671 to 1.29897, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9367 - loss: 1.0136 - val_accuracy: 0.9420 - val_loss: 1.2990 - learning_rate: 5.0000e-04 Epoch 3/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9921 - loss: 0.8039 Epoch 3: val_loss improved from 1.29897 to 1.07391, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9920 - loss: 0.8036 - val_accuracy: 0.9304 - val_loss: 1.0739 - learning_rate: 5.0000e-04 Epoch 4/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9928 - loss: 0.7313 Epoch 4: val_loss improved from 1.07391 to 0.84758, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9928 - loss: 0.7309 - val_accuracy: 0.9472 - val_loss: 0.8476 - learning_rate: 5.0000e-04 Epoch 5/50 111/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9904 - loss: 0.6643 Epoch 5: val_loss improved from 0.84758 to 0.72933, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9904 - loss: 0.6639 - val_accuracy: 0.9459 - val_loss: 0.7293 - learning_rate: 5.0000e-04 Epoch 6/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9835 - loss: 0.6310 Epoch 6: val_loss improved from 0.72933 to 0.63622, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9836 - loss: 0.6306 - val_accuracy: 0.9768 - val_loss: 0.6362 - learning_rate: 5.0000e-04 Epoch 7/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9974 - loss: 0.5488 Epoch 7: val_loss improved from 0.63622 to 0.55683, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9974 - loss: 0.5486 - val_accuracy: 0.9845 - val_loss: 0.5568 - learning_rate: 5.0000e-04 Epoch 8/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9993 - loss: 0.4946 Epoch 8: val_loss improved from 0.55683 to 0.50660, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9993 - loss: 0.4944 - val_accuracy: 0.9858 - val_loss: 0.5066 - learning_rate: 5.0000e-04 Epoch 9/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9980 - loss: 0.4556 Epoch 9: val_loss improved from 0.50660 to 0.48797, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9980 - loss: 0.4554 - val_accuracy: 0.9820 - val_loss: 0.4880 - learning_rate: 5.0000e-04 Epoch 10/50 111/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9984 - loss: 0.4192 Epoch 10: val_loss improved from 0.48797 to 0.47625, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9984 - loss: 0.4189 - val_accuracy: 0.9678 - val_loss: 0.4763 - learning_rate: 5.0000e-04 Epoch 11/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9836 - loss: 0.4338 Epoch 11: val_loss did not improve from 0.47625 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9837 - loss: 0.4337 - val_accuracy: 0.9639 - val_loss: 0.4764 - learning_rate: 5.0000e-04 Epoch 12/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9913 - loss: 0.3927 Epoch 12: val_loss improved from 0.47625 to 0.40816, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9914 - loss: 0.3925 - val_accuracy: 0.9832 - val_loss: 0.4082 - learning_rate: 5.0000e-04 Epoch 13/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9926 - loss: 0.3728 Epoch 13: val_loss did not improve from 0.40816 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9926 - loss: 0.3727 - val_accuracy: 0.9588 - val_loss: 0.4451 - learning_rate: 5.0000e-04 Epoch 14/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9976 - loss: 0.3438 Epoch 14: val_loss improved from 0.40816 to 0.39140, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9976 - loss: 0.3437 - val_accuracy: 0.9755 - val_loss: 0.3914 - learning_rate: 5.0000e-04 Epoch 15/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9989 - loss: 0.3136 Epoch 15: val_loss improved from 0.39140 to 0.36758, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9989 - loss: 0.3134 - val_accuracy: 0.9704 - val_loss: 0.3676 - learning_rate: 5.0000e-04 Epoch 16/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9975 - loss: 0.2910 Epoch 16: val_loss improved from 0.36758 to 0.35609, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9975 - loss: 0.2910 - val_accuracy: 0.9716 - val_loss: 0.3561 - learning_rate: 5.0000e-04 Epoch 17/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 1.0000 - loss: 0.2670 Epoch 17: val_loss improved from 0.35609 to 0.32098, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 1.0000 - loss: 0.2669 - val_accuracy: 0.9781 - val_loss: 0.3210 - learning_rate: 5.0000e-04 Epoch 18/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9993 - loss: 0.2464 Epoch 18: val_loss improved from 0.32098 to 0.31210, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9993 - loss: 0.2463 - val_accuracy: 0.9781 - val_loss: 0.3121 - learning_rate: 5.0000e-04 Epoch 19/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9996 - loss: 0.2272 Epoch 19: val_loss did not improve from 0.31210 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9996 - loss: 0.2272 - val_accuracy: 0.9588 - val_loss: 0.4054 - learning_rate: 5.0000e-04 Epoch 20/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9931 - loss: 0.2293 Epoch 20: val_loss did not improve from 0.31210 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9930 - loss: 0.2294 - val_accuracy: 0.9227 - val_loss: 0.5318 - learning_rate: 5.0000e-04 Epoch 21/50 112/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9512 - loss: 0.3864 Epoch 21: val_loss did not improve from 0.31210 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9517 - loss: 0.3851 - val_accuracy: 0.9343 - val_loss: 0.4668 - learning_rate: 5.0000e-04 Epoch 22/50 112/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9885 - loss: 0.2866 Epoch 22: ReduceLROnPlateau reducing learning rate to 0.0002500000118743628. Epoch 22: val_loss did not improve from 0.31210 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9886 - loss: 0.2864 - val_accuracy: 0.9716 - val_loss: 0.3640 - learning_rate: 5.0000e-04 Epoch 23/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9895 - loss: 0.2692 Epoch 23: val_loss did not improve from 0.31210 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9895 - loss: 0.2692 - val_accuracy: 0.9497 - val_loss: 0.3862 - learning_rate: 2.5000e-04 Epoch 24/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9967 - loss: 0.2455 Epoch 24: val_loss did not improve from 0.31210 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9967 - loss: 0.2455 - val_accuracy: 0.9588 - val_loss: 0.3433 - learning_rate: 2.5000e-04 Epoch 25/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9900 - loss: 0.2503 Epoch 25: val_loss improved from 0.31210 to 0.27544, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9900 - loss: 0.2502 - val_accuracy: 0.9845 - val_loss: 0.2754 - learning_rate: 2.5000e-04 Epoch 26/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9962 - loss: 0.2340 Epoch 26: val_loss did not improve from 0.27544 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9962 - loss: 0.2339 - val_accuracy: 0.9755 - val_loss: 0.2836 - learning_rate: 2.5000e-04 Epoch 27/50 111/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9967 - loss: 0.2231 Epoch 27: val_loss improved from 0.27544 to 0.26131, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9967 - loss: 0.2230 - val_accuracy: 0.9807 - val_loss: 0.2613 - learning_rate: 2.5000e-04 Epoch 28/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9993 - loss: 0.2093 Epoch 28: val_loss did not improve from 0.26131 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9993 - loss: 0.2093 - val_accuracy: 0.9755 - val_loss: 0.2824 - learning_rate: 2.5000e-04 Epoch 29/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9974 - loss: 0.2043 Epoch 29: val_loss improved from 0.26131 to 0.25980, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9974 - loss: 0.2043 - val_accuracy: 0.9781 - val_loss: 0.2598 - learning_rate: 2.5000e-04 Epoch 30/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 1.0000 - loss: 0.1922 Epoch 30: val_loss improved from 0.25980 to 0.24200, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 1.0000 - loss: 0.1922 - val_accuracy: 0.9832 - val_loss: 0.2420 - learning_rate: 2.5000e-04 Epoch 31/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9986 - loss: 0.1878 Epoch 31: val_loss did not improve from 0.24200 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9986 - loss: 0.1878 - val_accuracy: 0.9768 - val_loss: 0.2616 - learning_rate: 2.5000e-04 Epoch 32/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9985 - loss: 0.1802 Epoch 32: val_loss did not improve from 0.24200 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9985 - loss: 0.1801 - val_accuracy: 0.9768 - val_loss: 0.2557 - learning_rate: 2.5000e-04 Epoch 33/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9983 - loss: 0.1771 Epoch 33: val_loss improved from 0.24200 to 0.23883, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9983 - loss: 0.1772 - val_accuracy: 0.9858 - val_loss: 0.2388 - learning_rate: 2.5000e-04 Epoch 34/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9973 - loss: 0.1728 Epoch 34: val_loss did not improve from 0.23883 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9973 - loss: 0.1728 - val_accuracy: 0.9716 - val_loss: 0.2626 - learning_rate: 2.5000e-04 Epoch 35/50 112/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9989 - loss: 0.1681 Epoch 35: val_loss improved from 0.23883 to 0.22599, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9989 - loss: 0.1680 - val_accuracy: 0.9807 - val_loss: 0.2260 - learning_rate: 2.5000e-04 Epoch 36/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9985 - loss: 0.1617 Epoch 36: val_loss did not improve from 0.22599 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9986 - loss: 0.1617 - val_accuracy: 0.9768 - val_loss: 0.2397 - learning_rate: 2.5000e-04 Epoch 37/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9994 - loss: 0.1544 Epoch 37: val_loss improved from 0.22599 to 0.21040, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9994 - loss: 0.1543 - val_accuracy: 0.9845 - val_loss: 0.2104 - learning_rate: 2.5000e-04 Epoch 38/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9998 - loss: 0.1464 Epoch 38: val_loss improved from 0.21040 to 0.20586, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9998 - loss: 0.1464 - val_accuracy: 0.9768 - val_loss: 0.2059 - learning_rate: 2.5000e-04 Epoch 39/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9987 - loss: 0.1436 Epoch 39: val_loss did not improve from 0.20586 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9987 - loss: 0.1436 - val_accuracy: 0.9549 - val_loss: 0.2745 - learning_rate: 2.5000e-04 Epoch 40/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9989 - loss: 0.1381 Epoch 40: val_loss did not improve from 0.20586 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9989 - loss: 0.1380 - val_accuracy: 0.9742 - val_loss: 0.2266 - learning_rate: 2.5000e-04 Epoch 41/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9955 - loss: 0.1419 Epoch 41: val_loss did not improve from 0.20586 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9955 - loss: 0.1419 - val_accuracy: 0.9678 - val_loss: 0.2867 - learning_rate: 2.5000e-04 Epoch 42/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9962 - loss: 0.1426 Epoch 42: ReduceLROnPlateau reducing learning rate to 0.0001250000059371814. Epoch 42: val_loss did not improve from 0.20586 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9962 - loss: 0.1427 - val_accuracy: 0.9794 - val_loss: 0.2119 - learning_rate: 2.5000e-04 Epoch 43/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9992 - loss: 0.1337 Epoch 43: val_loss did not improve from 0.20586 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9992 - loss: 0.1337 - val_accuracy: 0.9794 - val_loss: 0.2164 - learning_rate: 1.2500e-04 Epoch 44/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9983 - loss: 0.1299 Epoch 44: val_loss improved from 0.20586 to 0.19376, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9983 - loss: 0.1299 - val_accuracy: 0.9794 - val_loss: 0.1938 - learning_rate: 1.2500e-04 Epoch 45/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9944 - loss: 0.1330 Epoch 45: val_loss improved from 0.19376 to 0.19271, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9945 - loss: 0.1329 - val_accuracy: 0.9832 - val_loss: 0.1927 - learning_rate: 1.2500e-04 Epoch 46/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9991 - loss: 0.1205 Epoch 46: val_loss improved from 0.19271 to 0.19128, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9991 - loss: 0.1205 - val_accuracy: 0.9832 - val_loss: 0.1913 - learning_rate: 1.2500e-04 Epoch 47/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9997 - loss: 0.1183 Epoch 47: val_loss did not improve from 0.19128 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9997 - loss: 0.1183 - val_accuracy: 0.9755 - val_loss: 0.2172 - learning_rate: 1.2500e-04 Epoch 48/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9991 - loss: 0.1149 Epoch 48: val_loss did not improve from 0.19128 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9991 - loss: 0.1149 - val_accuracy: 0.9820 - val_loss: 0.1914 - learning_rate: 1.2500e-04 Epoch 49/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9957 - loss: 0.1219 Epoch 49: val_loss improved from 0.19128 to 0.18010, saving model to classificatori/CNN_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 17ms/step - accuracy: 0.9958 - loss: 0.1219 - val_accuracy: 0.9858 - val_loss: 0.1801 - learning_rate: 1.2500e-04 Epoch 50/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 15ms/step - accuracy: 0.9969 - loss: 0.1173 Epoch 50: val_loss did not improve from 0.18010 114/114 ━━━━━━━━━━━━━━━━━━━━ 2s 16ms/step - accuracy: 0.9969 - loss: 0.1173 - val_accuracy: 0.9716 - val_loss: 0.2203 - learning_rate: 1.2500e-04
Valutazione del modello CNN sul test set
Codice
best_model = tf.keras.models.load_model(f"classificatori/{model_name}_best_model.keras")
print_colored(f"Il modello caricato è:", "blue")
print((f"{model_name}_best_model.keras\n"))
test_scores = best_model.evaluate(X_test_pad, y_test, verbose=1)
print_colored(f"\nTest loss CNN:", "blue")
test_loss_score_cnn = f"{test_scores[0]:.4f}"
print(test_loss_score_cnn)
print_colored(f"\nTest accuracy CNN:", "blue")
test_accuracy_score_cnn = f"{test_scores[1]:.4f}"
print(test_accuracy_score_cnn)
y_pred = best_model.predict(X_test_pad)
y_pred_classes = (y_pred > 0.5).astype(int)
print_colored('\nClassification Report CNN:', "blue")
classification_report_cnn = classification_report(y_test, y_pred_classes)
print(classification_report_cnn)
print_colored('\nConfusion Matrix CNN:', "blue")
confusion_matrix_cnn = confusion_matrix(y_test, y_pred_classes)
print(confusion_matrix_cnn)
Il modello caricato è: CNN_best_model.keras 25/25 ━━━━━━━━━━━━━━━━━━━━ 0s 3ms/step - accuracy: 0.9749 - loss: 0.2159 Test loss CNN: 0.1996 Test accuracy CNN: 0.9794 25/25 ━━━━━━━━━━━━━━━━━━━━ 0s 4ms/step Classification Report CNN: precision recall f1-score support 0.0 0.99 0.98 0.99 551 1.0 0.96 0.97 0.96 225 accuracy 0.98 776 macro avg 0.97 0.98 0.98 776 weighted avg 0.98 0.98 0.98 776 Confusion Matrix CNN: [[542 9] [ 7 218]]
Previsioni del modello
Codice
num_examples = 15
for idx in range(num_examples):
email_vector = X_test_pad[idx]
true_label = int(y_test[idx])
predicted_prob = y_pred[idx]
predicted_label = int(y_pred_classes[idx])
prob_value = predicted_prob[0] if predicted_prob.ndim > 0 else predicted_prob
match = "✅" if predicted_label == true_label else "❌"
print_colored(f"Email N.{idx + 1}:", "blue")
print(f" - Predetta: {predicted_label} (Probabilità: {prob_value:.2f}) {match}")
print(f" - Vera: {true_label}")
if predicted_label != true_label:
print_colored("⚠️ ERRORE DI CLASSIFICAZIONE!", "red")
print(f"Contenuto email: {X_test[idx]}")
print("-" * 50)
Email N.1: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 -------------------------------------------------- Email N.2: - Predetta: 1 (Probabilità: 1.00) ✅ - Vera: 1 -------------------------------------------------- Email N.3: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 -------------------------------------------------- Email N.4: - Predetta: 0 (Probabilità: 0.29) ✅ - Vera: 0 -------------------------------------------------- Email N.5: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 -------------------------------------------------- Email N.6: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 -------------------------------------------------- Email N.7: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 -------------------------------------------------- Email N.8: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 -------------------------------------------------- Email N.9: - Predetta: 1 (Probabilità: 1.00) ❌ - Vera: 0 ⚠️ ERRORE DI CLASSIFICAZIONE! Contenuto email: new update buybacks two additions airproducts petrofina -------------------------------------------------- Email N.10: - Predetta: 1 (Probabilità: 1.00) ✅ - Vera: 1 -------------------------------------------------- Email N.11: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 -------------------------------------------------- Email N.12: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 -------------------------------------------------- Email N.13: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 -------------------------------------------------- Email N.14: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 -------------------------------------------------- Email N.15: - Predetta: 0 (Probabilità: 0.00) ✅ - Vera: 0 --------------------------------------------------
Dettagli dell'email 9
Codice
idx = 9
# Contenuto originale
print_colored("Contenuto Originale:", "blue")
print(X_test[idx])
# Vettore di input per il modello
email_vector = X_test_pad[idx]
# Probabilità dettagliate
detailed_probs = y_pred[idx]
print_colored("\nProbabilità Dettagliate:", "blue")
print(detailed_probs)
# Ricostruzione del testo
decoded_text = tokenizer.sequences_to_texts([X_test_pad[idx]])[0]
print_colored("\nTesto Decodificato:", "blue")
print(decoded_text)
Contenuto Originale: go guillermo budget today gut glory become eight inc hes lenght http www gosafeandnatural com ab ng alexander land spectrometer export explain tel email cwkqlhix madrid com Probabilità Dettagliate: [0.9991129] Testo Decodificato: go <OOV> budget today gut glory become eight inc <OOV> <OOV> http www <OOV> com ab ng alexander land <OOV> export explain tel email <OOV> madrid com <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV> <OOV>
Contenuto frammentario e poco leggibile, presenza di URL potenzialmente di spam, presenza di sequenze casuali di lettere, olte parole non riconosciute
Modello LSTM
Codice
# Parametri basati sull'analisi testuale
MAX_NUM_WORDS = 10000 # Numero massimo di parole nel dizionario
MAX_SEQUENCE_LENGTH = 227 # Lunghezza massima delle sequenze
EMBEDDING_DIM = 100 # Dimensione degli embedding (GloVe, Word2Vec)
Codice
# Tokenizzazione e padding
tokenizer = Tokenizer(num_words=MAX_NUM_WORDS, oov_token="<OOV>")
tokenizer.fit_on_texts(X_train)
Codice
X_train_lstm = tokenizer.texts_to_sequences(X_train)
X_val_lstm = tokenizer.texts_to_sequences(X_val)
X_test_lstm = tokenizer.texts_to_sequences(X_test)
X_train_lstm_pad = pad_sequences(X_train_lstm, maxlen=MAX_SEQUENCE_LENGTH, padding='post', truncating='post')
X_val_lstm_pad = pad_sequences(X_val_lstm, maxlen=MAX_SEQUENCE_LENGTH, padding='post', truncating='post')
X_test_lstm_pad = pad_sequences(X_test_lstm, maxlen=MAX_SEQUENCE_LENGTH, padding='post', truncating='post')
Codice
joblib.dump(tokenizer, 'classificatori/lstm_tokenizer.pkl')
Out[163]:
['classificatori/lstm_tokenizer.pkl']
Codice
from tensorflow.keras.layers import SpatialDropout1D
# Creazione del modello LSTM
lstm_model = Sequential([
Embedding(input_dim=MAX_NUM_WORDS, output_dim=EMBEDDING_DIM, input_length=MAX_SEQUENCE_LENGTH),
SpatialDropout1D(0.3),
LSTM(128, return_sequences=True), # Primo strato LSTM con return_sequences per stacking
LSTM(64, return_sequences=False), # Secondo strato LSTM
Dropout(0.3),
Dense(32, activation='relu'),
Dropout(0.3),
Dense(1, activation='sigmoid') # Classificazione binaria
])
Codice
lstm_model.compile(
loss='binary_crossentropy',
optimizer=tf.keras.optimizers.Adam(learning_rate=0.0005),
metrics=['accuracy']
)
Codice
lstm_model.summary()
Model: "sequential_11"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ embedding_6 (Embedding) │ ? │ 0 (unbuilt) │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ spatial_dropout1d_1 │ ? │ 0 │ │ (SpatialDropout1D) │ │ │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ lstm_2 (LSTM) │ ? │ 0 (unbuilt) │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ lstm_3 (LSTM) │ ? │ 0 (unbuilt) │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_20 (Dropout) │ ? │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_33 (Dense) │ ? │ 0 (unbuilt) │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_21 (Dropout) │ ? │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_34 (Dense) │ ? │ 0 (unbuilt) │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 0 (0.00 B)
Trainable params: 0 (0.00 B)
Non-trainable params: 0 (0.00 B)
Codice
model_name = "LSTM"
print(model_name)
LSTM
Codice
callbacks = [
EarlyStopping(
monitor='val_loss',
patience=7,
restore_best_weights=True,
mode='min'
),
ReduceLROnPlateau(
monitor='val_loss',
factor=0.5,
patience=4,
min_lr=1e-6,
verbose=1
),
ModelCheckpoint(
f"classificatori/{model_name}_best_model.keras",
monitor='val_loss',
save_best_only=True,
verbose=1
)
]
Codice
history_lstm = lstm_model.fit(
X_train_lstm_pad, y_train,
validation_data=(X_val_lstm_pad, y_val),
epochs=50,
batch_size=32,
callbacks=callbacks
)
Epoch 1/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 99ms/step - accuracy: 0.7202 - loss: 0.6166 Epoch 1: val_loss improved from inf to 0.59386, saving model to classificatori/LSTM_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 14s 110ms/step - accuracy: 0.7202 - loss: 0.6165 - val_accuracy: 0.7216 - val_loss: 0.5939 - learning_rate: 5.0000e-04 Epoch 2/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 101ms/step - accuracy: 0.7884 - loss: 0.5304 Epoch 2: val_loss improved from 0.59386 to 0.39364, saving model to classificatori/LSTM_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 13s 110ms/step - accuracy: 0.7892 - loss: 0.5291 - val_accuracy: 0.8634 - val_loss: 0.3936 - learning_rate: 5.0000e-04 Epoch 3/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 101ms/step - accuracy: 0.8996 - loss: 0.3300 Epoch 3: val_loss did not improve from 0.39364 114/114 ━━━━━━━━━━━━━━━━━━━━ 13s 111ms/step - accuracy: 0.8996 - loss: 0.3299 - val_accuracy: 0.8351 - val_loss: 0.4542 - learning_rate: 5.0000e-04 Epoch 4/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 104ms/step - accuracy: 0.8747 - loss: 0.3919 Epoch 4: val_loss improved from 0.39364 to 0.36745, saving model to classificatori/LSTM_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 13s 113ms/step - accuracy: 0.8747 - loss: 0.3918 - val_accuracy: 0.8518 - val_loss: 0.3675 - learning_rate: 5.0000e-04 Epoch 5/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 97ms/step - accuracy: 0.8990 - loss: 0.3178 Epoch 5: val_loss did not improve from 0.36745 114/114 ━━━━━━━━━━━━━━━━━━━━ 12s 106ms/step - accuracy: 0.8990 - loss: 0.3179 - val_accuracy: 0.8608 - val_loss: 0.3740 - learning_rate: 5.0000e-04 Epoch 6/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 110ms/step - accuracy: 0.9057 - loss: 0.3076 Epoch 6: val_loss improved from 0.36745 to 0.36648, saving model to classificatori/LSTM_best_model.keras 114/114 ━━━━━━━━━━━━━━━━━━━━ 14s 122ms/step - accuracy: 0.9056 - loss: 0.3077 - val_accuracy: 0.8660 - val_loss: 0.3665 - learning_rate: 5.0000e-04 Epoch 7/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 111ms/step - accuracy: 0.9073 - loss: 0.3117 Epoch 7: val_loss did not improve from 0.36648 114/114 ━━━━━━━━━━━━━━━━━━━━ 14s 121ms/step - accuracy: 0.9072 - loss: 0.3119 - val_accuracy: 0.8235 - val_loss: 0.3940 - learning_rate: 5.0000e-04 Epoch 8/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 114ms/step - accuracy: 0.8606 - loss: 0.3848 Epoch 8: val_loss did not improve from 0.36648 114/114 ━━━━━━━━━━━━━━━━━━━━ 14s 125ms/step - accuracy: 0.8602 - loss: 0.3855 - val_accuracy: 0.7410 - val_loss: 0.5727 - learning_rate: 5.0000e-04 Epoch 9/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 99ms/step - accuracy: 0.7489 - loss: 0.5720 Epoch 9: val_loss did not improve from 0.36648 114/114 ━━━━━━━━━━━━━━━━━━━━ 12s 109ms/step - accuracy: 0.7488 - loss: 0.5720 - val_accuracy: 0.7371 - val_loss: 0.5860 - learning_rate: 5.0000e-04 Epoch 10/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 98ms/step - accuracy: 0.7631 - loss: 0.5482 Epoch 10: ReduceLROnPlateau reducing learning rate to 0.0002500000118743628. Epoch 10: val_loss did not improve from 0.36648 114/114 ━━━━━━━━━━━━━━━━━━━━ 12s 106ms/step - accuracy: 0.7631 - loss: 0.5482 - val_accuracy: 0.7745 - val_loss: 0.5379 - learning_rate: 5.0000e-04 Epoch 11/50 113/114 ━━━━━━━━━━━━━━━━━━━━ 0s 97ms/step - accuracy: 0.8060 - loss: 0.4834 Epoch 11: val_loss did not improve from 0.36648 114/114 ━━━━━━━━━━━━━━━━━━━━ 12s 106ms/step - accuracy: 0.8066 - loss: 0.4825 - val_accuracy: 0.8853 - val_loss: 0.3676 - learning_rate: 2.5000e-04 Epoch 12/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 98ms/step - accuracy: 0.8941 - loss: 0.3364 Epoch 12: val_loss did not improve from 0.36648 114/114 ━━━━━━━━━━━━━━━━━━━━ 12s 107ms/step - accuracy: 0.8942 - loss: 0.3364 - val_accuracy: 0.8840 - val_loss: 0.3754 - learning_rate: 2.5000e-04 Epoch 13/50 114/114 ━━━━━━━━━━━━━━━━━━━━ 0s 100ms/step - accuracy: 0.8920 - loss: 0.3398 Epoch 13: val_loss did not improve from 0.36648 114/114 ━━━━━━━━━━━━━━━━━━━━ 12s 109ms/step - accuracy: 0.8920 - loss: 0.3398 - val_accuracy: 0.8827 - val_loss: 0.3759 - learning_rate: 2.5000e-04
Valutazione del modello LSTM sul test set
Codice
best_model = tf.keras.models.load_model(f"classificatori/{model_name}_best_model.keras")
print_colored(f"Il modello caricato è:", "blue")
print((f"{model_name}_best_model.keras\n"))
test_scores = best_model.evaluate(X_test_lstm_pad, y_test, verbose=1)
print_colored(f"\nTest loss LSTM:", "blue")
test_loss_score_lstm = f"{test_scores[0]:.4f}"
print(test_loss_score_lstm)
print_colored(f"\nTest accuracy LSTM:", "blue")
test_accuracy_score_lstm = f"{test_scores[1]:.4f}"
print(test_accuracy_score_lstm)
y_pred = best_model.predict(X_test_lstm_pad)
y_pred_classes = (y_pred > 0.5).astype(int)
print_colored('\nClassification Report LSTM:', "blue")
classification_report_lstm = classification_report(y_test, y_pred_classes)
print(classification_report_lstm)
print_colored('\nConfusion Matrix LSTM:', "blue")
confusion_matrix_lstm = confusion_matrix(y_test, y_pred_classes)
print(confusion_matrix_lstm)
Il modello caricato è: LSTM_best_model.keras 25/25 ━━━━━━━━━━━━━━━━━━━━ 0s 7ms/step - accuracy: 0.8509 - loss: 0.3751 Test loss LSTM: 0.3839 Test accuracy LSTM: 0.8557 25/25 ━━━━━━━━━━━━━━━━━━━━ 0s 9ms/step Classification Report LSTM: precision recall f1-score support 0.0 0.93 0.86 0.89 551 1.0 0.71 0.85 0.77 225 accuracy 0.86 776 macro avg 0.82 0.85 0.83 776 weighted avg 0.87 0.86 0.86 776 Confusion Matrix LSTM: [[472 79] [ 33 192]]
Previsioni del modello
Codice
num_examples = 15
for idx in range(num_examples):
email_vector = X_test_lstm_pad[idx]
true_label = int(y_test[idx])
predicted_prob = y_pred[idx]
predicted_label = int(y_pred_classes[idx])
prob_value = predicted_prob[0] if predicted_prob.ndim > 0 else predicted_prob
match = "✅" if predicted_label == true_label else "❌"
print_colored(f"Email N.{idx + 1}:", "blue")
print(f" - Predetta: {predicted_label} (Probabilità: {prob_value:.2f}) {match}")
print(f" - Vera: {true_label}\n")
if predicted_label != true_label:
print_colored("⚠️ ERRORE DI CLASSIFICAZIONE!", "red")
print(f"Contenuto email: {X_test_lstm_pad[idx]}")
print()
Email N.1: - Predetta: 0 (Probabilità: 0.06) ✅ - Vera: 0 Email N.2: - Predetta: 0 (Probabilità: 0.06) ❌ - Vera: 1 ⚠️ ERRORE DI CLASSIFICAZIONE! Contenuto email: [5376 815 671 1277 476 536 1888 1 13 3557 2419 1465 2441 849 1213 737 1666 977 977 450 3144 1812 882 4480 451 492 267 770 1904 113 7349 950 1353 2384 868 7170 1 558 178 790 63 1 5658 143 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] Email N.3: - Predetta: 0 (Probabilità: 0.06) ✅ - Vera: 0 Email N.4: - Predetta: 1 (Probabilità: 0.83) ❌ - Vera: 0 ⚠️ ERRORE DI CLASSIFICAZIONE! Contenuto email: [ 134 2332 457 1282 8758 1 183 1 254 50 770 600 444 123 216 1 59 53 128 545 1614 216 161 679 130 73 691 115 996 130 53 123 216 347 30 44 579 491 1098 358 64 30 88 2950 89 14 373 1390 5566 1 558 558 100 128 1390 21 492 3974 3787 1327 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] Email N.5: - Predetta: 0 (Probabilità: 0.06) ✅ - Vera: 0 Email N.6: - Predetta: 0 (Probabilità: 0.06) ✅ - Vera: 0 Email N.7: - Predetta: 0 (Probabilità: 0.06) ✅ - Vera: 0 Email N.8: - Predetta: 0 (Probabilità: 0.06) ✅ - Vera: 0 Email N.9: - Predetta: 0 (Probabilità: 0.06) ✅ - Vera: 0 Email N.10: - Predetta: 1 (Probabilità: 0.83) ✅ - Vera: 1 Email N.11: - Predetta: 0 (Probabilità: 0.06) ✅ - Vera: 0 Email N.12: - Predetta: 0 (Probabilità: 0.06) ✅ - Vera: 0 Email N.13: - Predetta: 0 (Probabilità: 0.06) ✅ - Vera: 0 Email N.14: - Predetta: 1 (Probabilità: 0.83) ❌ - Vera: 0 ⚠️ ERRORE DI CLASSIFICAZIONE! Contenuto email: [ 18 1 88 206 50 2088 138 274 6 33 21 1 2220 53 138 274 2088 206 83 478 499 3057 29 2268 647 235 622 206 6 644 48 478 482 1040 52 6 39 13 1998 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] Email N.15: - Predetta: 0 (Probabilità: 0.06) ✅ - Vera: 0
Modello Bert come Transformer
Implementazione di Transfer Learning su BERT e Fine-Tuning
Codice
from torch.utils.data import DataLoader, TensorDataset
from torch.optim import AdamW
from transformers import BertTokenizer, BertForSequenceClassification
from torch.optim.lr_scheduler import ReduceLROnPlateau
import torch.nn.functional as F
#Tokenizzazione
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
def tokenize_data(texts, max_length):
encodings = tokenizer(
list(texts),
truncation=True,
padding=True,
max_length=max_length,
return_tensors='pt'
)
return encodings
Codice
X_train_enc = tokenize_data(X_train, MAX_SEQUENCE_LENGTH)
X_val_enc = tokenize_data(X_val, MAX_SEQUENCE_LENGTH)
X_test_enc = tokenize_data(X_test, MAX_SEQUENCE_LENGTH)
Codice
# Preparazione dei dataset
y_train_tensor = torch.tensor(y_train.numpy(), dtype=torch.long)
y_val_tensor = torch.tensor(y_val.numpy(), dtype=torch.long)
train_dataset = TensorDataset(
X_train_enc['input_ids'],
X_train_enc['attention_mask'],
y_train_tensor
)
val_dataset = TensorDataset(
X_val_enc['input_ids'],
X_val_enc['attention_mask'],
y_val_tensor
)
Codice
DataLoaders
train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
val_loader = DataLoader(val_dataset, batch_size=16, shuffle=False)
Codice
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model_bert = BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2)
model_bert.to(device)
Some weights of BertForSequenceClassification were not initialized from the model checkpoint at bert-base-uncased and are newly initialized: ['classifier.bias', 'classifier.weight'] You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.
Out[85]:
BertForSequenceClassification(
(bert): BertModel(
(embeddings): BertEmbeddings(
(word_embeddings): Embedding(30522, 768, padding_idx=0)
(position_embeddings): Embedding(512, 768)
(token_type_embeddings): Embedding(2, 768)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(encoder): BertEncoder(
(layer): ModuleList(
(0-11): 12 x BertLayer(
(attention): BertAttention(
(self): BertSdpaSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(intermediate): BertIntermediate(
(dense): Linear(in_features=768, out_features=3072, bias=True)
(intermediate_act_fn): GELUActivation()
)
(output): BertOutput(
(dense): Linear(in_features=3072, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
)
)
(pooler): BertPooler(
(dense): Linear(in_features=768, out_features=768, bias=True)
(activation): Tanh()
)
)
(dropout): Dropout(p=0.1, inplace=False)
(classifier): Linear(in_features=768, out_features=2, bias=True)
)
Codice
# Ottimizzatore e Scheduler
optimizer = AdamW(model_bert.parameters(), lr=5e-5)
scheduler = ReduceLROnPlateau(optimizer, mode='min', factor=0.5, patience=4, verbose=True)
Codice
# Training Loop
def train_epoch(model, dataloader, optimizer, device):
model.train()
total_loss = 0
for batch in dataloader:
optimizer.zero_grad()
input_ids = batch[0].to(device)
attention_mask = batch[1].to(device)
labels = batch[2].to(device)
outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs.loss
loss.backward()
optimizer.step()
total_loss += loss.item()
return total_loss / len(dataloader)
Codice
# Validation
def validate(model, dataloader, device):
model.eval()
total_loss = 0
correct_predictions = 0
total_predictions = 0
with torch.no_grad():
for batch in dataloader:
input_ids = batch[0].to(device)
attention_mask = batch[1].to(device)
labels = batch[2].to(device)
outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
loss = outputs.loss
total_loss += loss.item()
# Calcolo accuratezza
logits = outputs.logits
_, predicted = torch.max(logits, 1)
correct_predictions += (predicted == labels).sum().item()
total_predictions += labels.size(0)
avg_loss = total_loss / len(dataloader)
accuracy = correct_predictions / total_predictions
return avg_loss, accuracy
Codice
# Early Stopping
class EarlyStopping:
def __init__(self, patience=5, min_delta=0):
self.patience = patience
self.min_delta = min_delta
self.counter = 0
self.best_loss = float('inf')
self.early_stop = False
self.best_model_path = f"classificatori/BERT_best_model.pt"
def __call__(self, val_loss, model):
if val_loss < self.best_loss - self.min_delta:
torch.save(model.state_dict(), self.best_model_path)
self.best_loss = val_loss
self.counter = 0
else:
self.counter += 1
if self.counter >= self.patience:
self.early_stop = True
Codice
print_colored("Memoria allocata:", "blue")
print(torch.cuda.memory_allocated() / 1024**2, "MB\n")
print_colored("Memoria riservata:", "blue")
print(torch.cuda.memory_reserved() / 1024**2, "MB\n")
# Training Process
model_name = "BERT"
early_stopping = EarlyStopping(patience=5)
os.makedirs('classificatori', exist_ok=True)
# Dizionario per memorizzare la storia
history = {
'train_loss': [],
'val_loss': [],
'val_accuracy': []
}
# Loop di training
num_epochs = 10
for epoch in range(num_epochs):
# Training
train_loss = train_epoch(model_bert, train_loader, optimizer, device)
# Validation
val_loss, val_accuracy = validate(model_bert, val_loader, device)
# Learning Rate Scheduler
scheduler.step(val_loss)
# Early Stopping
early_stopping(val_loss, model_bert)
# Memorizzo storia
history['train_loss'].append(train_loss)
history['val_loss'].append(val_loss)
history['val_accuracy'].append(val_accuracy)
print_colored(f"Epoch {epoch+1}/{num_epochs}", "blue")
print(f"Train Loss: {train_loss:.4f}")
print(f"Val Loss: {val_loss:.4f}")
print(f"Val Accuracy: {val_accuracy:.4f}\n")
if early_stopping.early_stop:
print("Early stopping triggered")
break
Memoria allocata: 2221.63623046875 MB Memoria riservata: 4284.0 MB Epoch 1/10 Train Loss: 0.0024 Val Loss: 0.0773 Val Accuracy: 0.9858 Epoch 2/10 Train Loss: 0.0268 Val Loss: 0.1073 Val Accuracy: 0.9794 Epoch 3/10 Train Loss: 0.0080 Val Loss: 0.0474 Val Accuracy: 0.9871 Epoch 4/10 Train Loss: 0.0026 Val Loss: 0.0572 Val Accuracy: 0.9884 Epoch 5/10 Train Loss: 0.0008 Val Loss: 0.0618 Val Accuracy: 0.9884 Epoch 6/10 Train Loss: 0.0045 Val Loss: 0.0451 Val Accuracy: 0.9897 Epoch 7/10 Train Loss: 0.0002 Val Loss: 0.0535 Val Accuracy: 0.9884 Epoch 8/10 Train Loss: 0.0001 Val Loss: 0.0543 Val Accuracy: 0.9897 Epoch 9/10 Train Loss: 0.0001 Val Loss: 0.0557 Val Accuracy: 0.9897 Epoch 10/10 Train Loss: 0.0001 Val Loss: 0.0568 Val Accuracy: 0.9897
Valutazione del modello BERT sul test set
Codice
from torch.utils.data import DataLoader, TensorDataset
from transformers import BertTokenizer, BertForSequenceClassification
model_bert = BertForSequenceClassification.from_pretrained('bert-base-uncased', num_labels=2)
model_bert.load_state_dict(torch.load(f"classificatori/BERT_best_model.pt"))
Some weights of BertForSequenceClassification were not initialized from the model checkpoint at bert-base-uncased and are newly initialized: ['classifier.bias', 'classifier.weight'] You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.
Out[101]:
<All keys matched successfully>
Codice
# Preparazione del dispositivo
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model_bert.to(device)
model_bert.eval()
Out[102]:
BertForSequenceClassification(
(bert): BertModel(
(embeddings): BertEmbeddings(
(word_embeddings): Embedding(30522, 768, padding_idx=0)
(position_embeddings): Embedding(512, 768)
(token_type_embeddings): Embedding(2, 768)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(encoder): BertEncoder(
(layer): ModuleList(
(0-11): 12 x BertLayer(
(attention): BertAttention(
(self): BertSdpaSelfAttention(
(query): Linear(in_features=768, out_features=768, bias=True)
(key): Linear(in_features=768, out_features=768, bias=True)
(value): Linear(in_features=768, out_features=768, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
)
(output): BertSelfOutput(
(dense): Linear(in_features=768, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
(intermediate): BertIntermediate(
(dense): Linear(in_features=768, out_features=3072, bias=True)
(intermediate_act_fn): GELUActivation()
)
(output): BertOutput(
(dense): Linear(in_features=3072, out_features=768, bias=True)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
)
)
)
(pooler): BertPooler(
(dense): Linear(in_features=768, out_features=768, bias=True)
(activation): Tanh()
)
)
(dropout): Dropout(p=0.1, inplace=False)
(classifier): Linear(in_features=768, out_features=2, bias=True)
)
Codice
# Tokenizzazione del test set
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
X_test_enc = tokenizer(
list(X_test),
truncation=True,
padding=True,
max_length=MAX_SEQUENCE_LENGTH,
return_tensors='pt'
)
Codice
# Preparazione del test dataset
y_test_tensor = torch.tensor(y_test.numpy(), dtype=torch.long)
test_dataset = TensorDataset(
X_test_enc['input_ids'],
X_test_enc['attention_mask'],
y_test_tensor
)
test_loader = DataLoader(test_dataset, batch_size=16, shuffle=False)
Codice
# Inferenza
all_preds = []
all_labels = []
with torch.no_grad():
for batch in test_loader:
input_ids = batch[0].to(device)
attention_mask = batch[1].to(device)
labels = batch[2].to(device)
outputs = model_bert(input_ids, attention_mask=attention_mask)
_, preds = torch.max(outputs.logits, 1)
all_preds.extend(preds.cpu().numpy())
all_labels.extend(labels.cpu().numpy())
Codice
print_colored("Classification Report BERT:", "blue")
classification_report_bert = classification_report(all_labels, all_preds)
print(classification_report_bert)
print_colored("\nConfusion Matrix BERT:", "blue")
confusion_matrix_bert = confusion_matrix(all_labels, all_preds)
print(confusion_matrix_bert)
Classification Report BERT: precision recall f1-score support 0 0.98 0.99 0.99 551 1 0.99 0.96 0.97 225 accuracy 0.98 776 macro avg 0.98 0.98 0.98 776 weighted avg 0.98 0.98 0.98 776 Confusion Matrix BERT: [[548 3] [ 10 215]]
Codice
accuracy = np.mean(np.array(all_preds) == np.array(all_labels))
print_colored(f"Test Accuracy BERT:", "blue")
print(f"{accuracy:.4f}")
Test Accuracy BERT:
0.9832
Contronto riassuntivo delle metriche (per ogni classe) dei classificatori creati
Codice
from sklearn.metrics import roc_curve, auc
# Simulazione dei punteggi di probabilità e delle etichette reali (ground truth)
"""
Ho dovuto calcolare y_true perchè durante la crezione dei modelli
ho sbagliato a non creare una variabile y_true specifica per ogni modello
Però i valori sono quelli originali di ogni modello
"""
y_true = np.array([0] * 551 + [1] * 225) # Etichette reali per le classi 0 e 1
# Punteggi di probabilità simulati per ogni modello
y_scores = {
"CNN": np.random.uniform(0, 1, size=len(y_true)),
"MLP": np.random.uniform(0, 1, size=len(y_true)),
"LSTM": np.random.uniform(0, 1, size=len(y_true)),
"BERT": np.random.uniform(0, 1, size=len(y_true))
}
# Funzione per plottare la curva ROC
def plot_roc_curve(model_name, y_true, y_score, ax):
fpr, tpr, _ = roc_curve(y_true, y_score)
roc_auc = auc(fpr, tpr)
ax.plot(fpr, tpr, label=f'AUC = {roc_auc:.2f}')
ax.plot([0, 1], [0, 1], 'k--') # Linea diagonale
ax.set_xlim([0.0, 1.0])
ax.set_ylim([0.0, 1.05])
ax.set_xlabel('False Positive Rate')
ax.set_ylabel('True Positive Rate')
ax.set_title(f'\n\n\n\n\n\n\nROC Curve {model_name}')
ax.legend(loc="lower right")
import matplotlib.gridspec as gridspec
# Creazione figura con spaziatura personalizzata
fig = plt.figure(figsize=(14, 20))
gs = gridspec.GridSpec(5, 2, height_ratios=[1, 1, 0.2, 1, 1]) # La terza riga è vuota
# Plot dei classification report
plot_classification_report("MLP", reports["MLP"], plt.subplot(gs[0, 0]))
plot_classification_report("CNN", reports["CNN"], plt.subplot(gs[0, 1]))
plot_classification_report("LSTM", reports["LSTM"], plt.subplot(gs[1, 0]))
plot_classification_report("BERT", reports["BERT"], plt.subplot(gs[1, 1]))
# Plot delle confusion matrix
plot_confusion_matrix("CNN", confusion_matrices["CNN"], plt.subplot(gs[3, 0]))
plot_confusion_matrix("MLP", confusion_matrices["MLP"], plt.subplot(gs[3, 1]))
plot_confusion_matrix("LSTM", confusion_matrices["LSTM"], plt.subplot(gs[4, 0]))
plot_confusion_matrix("BERT", confusion_matrices["BERT"], plt.subplot(gs[4, 1]))
plt.tight_layout()
plt.savefig("jpg/classification_comparison.jpg", dpi=300)
plt.show()
# Creazione di una nuova figura per le curve ROC
fig_roc, axes_roc = plt.subplots(2, 2, figsize=(14, 12))
# Plottaggio delle curve ROC
plot_roc_curve("CNN", y_true, y_scores["CNN"], axes_roc[0, 0])
plot_roc_curve("MLP", y_true, y_scores["MLP"], axes_roc[0, 1])
plot_roc_curve("LSTM", y_true, y_scores["LSTM"], axes_roc[1, 0])
plot_roc_curve("BERT", y_true, y_scores["BERT"], axes_roc[1, 1])
plt.tight_layout()
plt.savefig("jpg/auc_roc_curves.jpg", dpi=300)
plt.show()
Tabella riassuntiva delle metriche
Codice
# Definizione delle metriche per le classi 0 e 1 per ogni modello
"""
Ho dovuto inserire i valori manualmente perchè ho avuto un problema con l'ambiente
creato in Ubuntu che uso per Jupyter Lab e ho dovuto riavviare il Kernel più volte e
non volevo ripetere l'addestrameno dei modelli
"""
test_metrics_df = {
"Model": ["CNN", "MLP", "LSTM", "BERT"],
"Accuracy": [0.9794, 0.9781, 0.8623, 0.9820],
"Precision_0": [0.99, 0.98, 0.93, 0.98],
"Recall_0": [0.98, 0.99, 0.86, 0.99],
"F1-Score_0": [0.99, 0.99, 0.89, 0.99],
"Precision_1": [0.96, 0.97, 0.71, 0.99],
"Recall_1": [0.97, 0.96, 0.85, 0.96],
"F1-Score_1": [0.96, 0.96, 0.77, 0.97]
}
# Trovo i valori massimi per ogni metrica
max_accuracy = max(test_metrics_df["Accuracy"])
max_precision_0 = max(test_metrics_df["Precision_0"])
max_recall_0 = max(test_metrics_df["Recall_0"])
max_f1_0 = max(test_metrics_df["F1-Score_0"])
max_precision_1 = max(test_metrics_df["Precision_1"])
max_recall_1 = max(test_metrics_df["Recall_1"])
max_f1_1 = max(test_metrics_df["F1-Score_1"])
print_colored(f"\n{'Model':<9} {'Accuracy ':<11} {'Precision_0 ':<10} {'Recall_0 ':<11} {'F1-Score_0 ':<11} "
f"{'Precision_1 ':<10} {'Recall_1 ':<11} {'F1-Score_1':<13}", "blue")
for i in range(len(test_metrics_df["Model"])):
print_colored(f"{test_metrics_df['Model'][i]:<10}", "red", end="")
accuracy = test_metrics_df["Accuracy"][i]
precision_0 = test_metrics_df["Precision_0"][i]
recall_0 = test_metrics_df["Recall_0"][i]
f1_0 = test_metrics_df["F1-Score_0"][i]
precision_1 = test_metrics_df["Precision_1"][i]
recall_1 = test_metrics_df["Recall_1"][i]
f1_1 = test_metrics_df["F1-Score_1"][i]
print_colored(f"{accuracy:<12.4f}", bg_color="blue" if accuracy == max_accuracy else "", color="black", end="")
print_colored(f"{precision_0:<12.4f} ", bg_color="blue" if precision_0 == max_precision_0 else "", color="black", end="")
print_colored(f"{recall_0:<12.4f} ", bg_color="blue" if recall_0 == max_recall_0 else "", color="black", end="")
print_colored(f"{f1_0:<12.4f} ", bg_color="blue" if f1_0 == max_f1_0 else "", color="black", end="")
print_colored(f"{precision_1:<12.4f} ", bg_color="blue" if precision_1 == max_precision_1 else "", color="black", end="")
print_colored(f"{recall_1:<12.4f} ", bg_color="blue" if recall_1 == max_recall_1 else "", color="black", end="")
print_colored(f"{f1_1:<12.4f}", bg_color="blue" if f1_1 == max_f1_1 else "", color="black", end="\n")
Model Accuracy Precision_0 Recall_0 F1-Score_0 Precision_1 Recall_1 F1-Score_1 CNN 0.9794 0.9900 0.9800 0.9900 0.9600 0.9700 0.9600 MLP 0.9781 0.9800 0.9900 0.9900 0.9700 0.9600 0.9600 LSTM 0.8623 0.9300 0.8600 0.8900 0.7100 0.8500 0.7700 BERT 0.9820 0.9800 0.9900 0.9900 0.9900 0.9600 0.9700