Спам проти нормальних повідомлень: Створення класифікатора спаму за допомогою машинного навчання та обробки природної мови

У цьому блозі я проведу вас через просту, але захоплюючу подорож зі створення системи виявлення спаму за допомогою машинного навчання. Завдання, яке ми вирішуємо, полягає в класифікації SMS-повідомлень на спам (небажані повідомлення) і хем (неспам-повідомлення). Це завдання стало основою в обробці природної мови (NLP) для дослідження таких технік машинного навчання, як витягування ознак, оцінка моделей та налаштування гіперпараметрів.

Початок роботи: Імпортування необхідних бібліотек

import pandas as pd  
import numpy as np  
import matplotlib.pyplot as plt  
import seaborn as sns  
import wordcloud  
import nltk  
from nltk.corpus import stopwords  
from nltk.tokenize import word_tokenize  
from sklearn.naive_bayes import MultinomialNB  
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix  
from sklearn.feature_extraction.text import TfidfVectorizer  
from sklearn.model_selection import train_test_split, GridSearchCV  
import joblib

Завантаження та підготовка набору даних

# Завантаження набору даних SMS Spam Collection  
with open('/path/to/SMSSpamCollection', 'r', encoding='latin-1') as file:  
 lines = file.readlines()  
# Розділяємо рядки за мітками (ham/spam) та повідомленнями  
data = []  
for line in lines:  
 label, message = line.split("\t") # Розділяємо рядок на мітку та повідомлення  
 data.append([label.strip(), message.strip()])  
# Перетворення на DataFrame  
data = pd.DataFrame(data, columns=['label', 'text'])

Далі ми відображаємо мітки ham та spam як числові значення (0 для хем і 1 для спаму), що робить їх придатними для моделей машинного навчання:

data['label'] = data['label'].map({'ham': 0, 'spam': 1})

Попередній аналіз даних (EDA)

Завжди корисно візуалізувати набір даних і зрозуміти його структуру перед тим, як розпочати тренування моделі. Ми можемо почати з вивчення розподілу ham та spam повідомлень:

data.label.value_counts().plot.bar()

pic

# знайдемо довжину повідомлень  
data['length'] = data['text'].apply(len)  
print(data)  

label text length  
0 0 Go until jurong point, crazy.. Available only ... 111  
1 0 Ok lar... Joking wif u oni... 29  
2 1 Free entry in 2 a wkly comp to win FA Cup fina... 155  
3 0 U dun say so early hor... U c already then say... 49  
4 0 Nah I don't think he goes to usf, he lives aro... 61  
... ... ... ...  
5569 1 This is the 2nd time we have tried 2 contact u... 161  
5570 0 Will ü b going to esplanade fr home? 37  
5571 0 Pity, * was in mood for that. So...any other s... 57  
5572 0 The guy did some bitching but I acted like i'd... 125  
5573 0 Rofl. Its true to its name 26

Попередня обробка тексту

Попередня обробка тексту є важливим етапом в NLP.
У цьому блозі я проведу вас через просту, але захоплюючу подорож зі створення системи виявлення спаму за допомогою машинного навчання. Завдання, яке ми вирішуємо, полягає в класифікації SMS-повідомлень на спам (небажані повідомлення) і хем (неспам-повідомлення). Це завдання стало основою в обробці природної мови (NLP) для дослідження таких технік машинного навчання, як витягування ознак, оцінка моделей та налаштування гіперпараметрів.

Початок роботи: Імпортування необхідних бібліотек

import pandas as pd  
import numpy as np  
import matplotlib.pyplot as plt  
import seaborn as sns  
import wordcloud  
import nltk  
from nltk.corpus import stopwords  
from nltk.tokenize import word_tokenize  
from sklearn.naive_bayes import MultinomialNB  
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix  
from sklearn.feature_extraction.text import TfidfVectorizer  
from sklearn.model_selection import train_test_split, GridSearchCV  
import joblib

Завантаження та підготовка набору даних

# Завантаження набору даних SMS Spam Collection  
with open('/path/to/SMSSpamCollection', 'r', encoding='latin-1') as file:  
 lines = file.readlines()  
# Розділяємо рядки за мітками (ham/spam) таt") # Розділяємо рядок на мітку та повідомлення  
 data.append([label.strip(), message.strip()])  
# Перетворення на DataFrame  
data = pd.DataFrame(data, columns=['label', 'text'])

Далі ми відображаємо мітки ham та spam як числові значення (0 для хем і 1 для спаму), що робить їх придатними для моделей машинного навчання:

data['label'] = data['label'].map({'ham': 0, 'spam': 1})

Попередній аналіз даних (EDA)

Завжди корисно візуалізувати набір даних і зрозуміти його структуру перед тим, як розпочати тренування моделі. Ми можемо почати з вивчення розподілу ham та spam повідомлень:

data.label.value_counts().plot.bar()

pic

# знайдемо довжину повідомлень  
data['length'] = data['text'].apply(len)  
print(data)  

label text length  
0 0 Go until jurong point, crazy.. Available only ... 111  
1 0 Ok lar... Joking wif u oni... 29  
2 1 Free entry in 2 a wkly comp to win FA Cup fina... 155  
3 0 U dun say so early hor... U c already then say... 49  
4 0 Nah I don't think he goes to usf, he lives aro... 61  
... ... ... ...  
5569 1 This is the 2nd time we have tried 2 contact u... 161  
5570 0 Will ü b going to esplanade fr home? 37  
5571 0 Pity, * was in mood for that. So...any other s... 57  
5572 0 The guy did some bitching but I acted like i'd... 125  
5573 0 Rofl. Its true to its name 26

Попередня обробка тексту

Попередня обробка тексту є важливим етапом в NLP.
Тут ми видаляємо непотрібні символи, токенізуємо текст та видаляємо стоп-слова, щоб підготувати дані для навчання моделі.

# Завантажуємо необхідні ресурси NLTK  
nltk.download('punkt')  
nltk.download('stopwords')  
nltk.download('punkt_tab') # Завантажуємо ресурс punkt_tab  

# Оголошуємо функцію для попередньої обробки тексту  
def preprocess_text(text):  
 # Перетворюємо на малі літери  
 text = text.lower()  
 # Токенізуємо текст  
 tokens = word_tokenize(text)  
 # Видаляємо стоп-слова  
 stop_words = set(stopwords.words('english'))  
 tokens = [word for word in tokens if word.isalnum() and word not in stop_words]  
 return " ".join(tokens)  

# Застосовуємо попередню обробку до даних як для хем, так і для спаму  
data['text'] = data['text'].apply(preprocess_text)

Витягування ознак за допомогою TF-IDF

Щоб перетворити текст у числові дані, які можна використовувати для алгоритмів машинного навчання, ми використовуємо TF-IDF (Частота терміну - Обернена частота документів).

# Ініціалізуємо TfidfVectorizer  
vectorizer = TfidfVectorizer(max_features=5000, stop_words='english')  
X = vectorizer.fit_transform(data['text']).toarray()

Навчання моделі: Класифікатор наївного баєса

# Розділяємо дані на тренувальний та тестовий набори  
X_train, X_test, y_train, y_test = train_test_split(X, data['label'], test_size=0.2, random_state=42)  

# Ініціалізуємо модель  
model = MultinomialNB()  

# Навчаємо модель  
model.fit(X_train, y_train)

Оцінка моделі

# Робимо прогнози на тестовому наборі  
y_pred = model.predict(X_test)  

# Оцінюємо модель  
accuracy = accuracy_score(y_test, y_pred)  
print(f"Точність: {accuracy * 100:.2f}%")  

# Виводимо звіт про класифікацію  
print("Звіт про класифікацію:\n", classification_report(y_test, y_pred))  

# Матриця сплутаних класів  
conf_matrix = confusion_matrix(y_test, y_pred)  
sns.heatmap(conf_matrix, annot=True, fmt="d", cmap="Blues", xticklabels=['Ham', 'Spam'], yticklabels=['Ham', 'Spam'])  
plt.xlabel('Прогнозоване')  
plt.ylabel('Правдиве')  
plt.title('Матриця сплутаних класів')  
plt.show()
Точність: 97.67%  
Звіт про класифікацію:  
 precision recall f1-score support  

 0 0.97 1.00 0.99 954  
 1 1.00 0.84 0.91 161  

 accuracy 0.98 1115  
 macro avg 0.99 0.92 0.95 1115  
weighted avg 0.98 0.98 0.98 1115

pic

Налаштування гіперпараметрів за допомогою GridSearchCV

Щоб ще більше покращити нашу модель, ми можемо виконати налаштування гіперпараметрів.
Тут ми видаляємо непотрібні символи, токенізуємо текст і видаляємо стоп-слова, щоб підготувати дані для навчання моделі.

# Завантажуємо необхідні ресурси NLTK  
nltk.download('punkt')  
nltk.download('stopwords')  
nltk.download('punkt_tab') # Завантажуємо ресурс punkt_tab  

# Оголошуємо функцію для попередньої обробки тексту  
def preprocess_text(text):  
 # Перетворюємо на малі літери  
 text = text.lower()  
 # Токенізуємо текст  
 tokens = word_tokenize(text)  
 # Видаляємо стоп-слова  
 stop_words = set(stopwords.words('english'))  
 tokens = [word for word in tokens if word.isalnum() and word not in stop_words]  
 return " ".join(tokens)  

# Застосовуємо попередню обробку до даних як для хем, так і для спаму  
data['text'] = data['text'].apply(preprocess_text)

Витягування ознак за допомогою TF-IDF

Щоб перетворити текст у числові дані, які можна використовувати для алгоритмів машинного навчання, ми використовуємо TF-IDF (Частота терміну - Обернена частота документів).

# Ініціалізуємо TfidfVectorizer  
vectorizer = TfidfVectorizer(max_features=5000, stop_words='english')  
X = vectorizer.fit_transform(data['text']).toarray()

Навчання моделі: Класифікатор наївного баєса

# Розділяємо дані на тренувальний та тестовий набори  
X_train, X_test, y_train, y_test = train_test_split(X, data['label'], test_size=0.2, random_state=42)  

# Ініціалізуємо модель  
model = MultinomialNB()  

# Навчаємо модель  
model.fit(X_train, y_train)

Оцінка моделі

# Робимо прогнози на тестовому наборі  
y_pred = model.predict(X_test)  

# Оцінюємо модель  
accuracy = accuracy_score(y_test, y_pred)  
print(f"Точність: {accuracy * 100:.2f}%")  

# Виводимо звіт про класифікацію  
print("Звіт про класифікацію:\n", classification_report(y_test, y_pred))  

# Матриця сплутаних класів  
conf_matrix = confusion_matrix(y_test, y_pred)  
sns.heatmap(conf_matrix, annot=True, fmt="d", cmap="Blues", xticklabels=['Ham', 'Spam'], yticklabels=['Ham', 'Spam'])  
plt.xlabel('Прогнозоване')  
plt.ylabel('Правдиве')  
plt.title('Матриця сплутаних класів')  
plt.show()
Точність: 97.67%  
Звіт про класифікацію:  
 precision recall f1-score support  

 0 0.97 1.00 0.99 954  
 1 1.00 0.84 0.91 161  

 accuracy 0.98 1115  
 macro avg 0.99 0.92 0.95 1115  
weighted avg 0.98 0.98 0.98 1115

pic

Налаштування гіперпараметрів за допомогою GridSearchCV

Щоб ще більше покращити нашу модель, ми можемо виконати налаштування гіперпараметрів.
Використовуючи GridSearchCV, ми можемо знайти найкраще значення для параметра згладжування (alpha) класифікатора наївного баєса.

# Оголошуємо параметри для Naive Bayes  
param_grid = {'alpha': [0.1, 0.5, 1, 2, 5]}  

# GridSearchCV  
grid_search = GridSearchCV(MultinomialNB(), param_grid, cv=5, n_jobs=-1)  
grid_search.fit(X_train, y_train)  

# Найкращі параметри, знайдені GridSearchCV  
print("Найкращі параметри:", grid_search.best_params_)
# Отримуємо найкраще значення alpha з GridSearchCV  
best_alpha = grid_search.best_params_['alpha']  

# Ініціалізуємо класифікатор Naive Bayes з найкращим alpha  
model = MultinomialNB(alpha=best_alpha)  

# Повторно навчаємо модель з тренувальними даними  
model.fit(X_train, y_train)  

# Робимо прогнози на тестовому наборі  
y_pred = model.predict(X_test)  

# Оцінюємо точність моделі  
accuracy = accuracy_score(y_test, y_pred)  
print(f"Точність після повторного навчання: {accuracy * 100:.2f}%")  

# Виводимо звіт про класифікацію  
print("Звіт про класифікацію:\n", classification_report(y_test, y_pred))  

# Матриця сплутаних класів  
conf_matrix = confusion_matrix(y_test, y_pred)  
sns.heatmap(conf_matrix, annot=True, fmt="d", cmap="Blues", xticklabels=['Ham', 'Spam'], yticklabels=['Ham', 'Spam'])  
plt.xlabel('Прогнозоване')  
plt.ylabel('Правдиве')  
plt.title('Матриця сплутаних класів')  
plt.show()
Точність після повторного навчання: 98.30%  
Звіт про класифікацію:  
 precision recall f1-score support  

 0 0.99 0.99 0.99 954  
 1 0.97 0.91 0.94 161  

 accuracy 0.98 1115  
 macro avg 0.98 0.95 0.96 1115  
weighted avg 0.98 0.98 0.98 1115

pic

Збереження моделі для розгортання

Щоб зробити нашу модель доступною для подальшого використання, ми можемо зберегти її за допомогою joblib. Це дозволить нам завантажити модель і векторизатор пізніше для прогнозів.

# Зберігаємо модель та векторизатор  
joblib.dump(model, 'spam_classifier_model.pkl')  
joblib.dump(vectorizer, 'tfidf_vectorizer.pkl')
# Зберігаємо навчану модель у файл (наприклад, model.joblib)  
joblib.dump(model, 'model.joblib')  

# Зберігаємо векторизатор (якщо використовується) для витягування ознак таким самим чином  
joblib.dump(vectorizer, 'vectorizer.joblib')

Висновок

У цьому пості ми успішно створили простий, але ефективний класифікатор спаму за допомогою технік машинного навчання. Ми охопили всі етапи: від завантаження і підготовки даних, до попередньої обробки тексту, навчання класифікатора наївного баєса та оцінки продуктивності моделі. Також ми дослідили, як налаштування гіперпараметрів може ще більше оптимізувати модель.

Але на цьому веселість не закінчується! Слідкуйте за наступною фазою цього проєкту — розгортанням моделі локально за допомогою Flask і Streamlit для створення інтерактивного досвіду для користувачів. Крім того, ми розглянемо більш складні моделі, такі як BERT і LoRA (Low-Rank Adaptation), які обіцяють ще кращу продуктивність для завдань NLP. Ці моделі також будуть розгорнуті локально, покращуючи загальний досвід.

Дякую за прочитане! Не соромтеся залишати коментарі чи питання нижче, і я із задоволенням обговорю чи уточню будь-яку частину цього процесу.

Це мій другий пост на Medium, і я планую опублікувати щонайменше 100 постів. Будь ласка, поставте лайк, якщо це було корисно!

Я спеціалізуюсь на AI, ML, DL, NLP та LLM, і я відкритий для індивідуальних проєктів. Незалежно від того, чи це пов'язано з індустрією, чи з академічними дослідженнями, я можу допомогти втілити ваші ідеї в реальність.
Використовуючи GridSearchCV, ми можемо знайти найкраще значення для параметра згладжування (alpha) класифікатора наївного баєса.

# Оголошуємо параметри для Naive Bayes  
param_grid = {'alpha': [0.1, 0.5, 1, 2, 5]}  

# GridSearchCV  
grid_search = GridSearchCV(MultinomialNB(), param_grid, cv=5, n_jobs=-1)  
grid_search.fit(X_train, y_train)  

# Найкращі параметри, знайдені GridSearchCV  
print("Найкращі параметри:", grid_search.best_params_)
# Отримуємо найкраще значення alpha з GridSearchCV  
best_alpha = grid_search.best_params_['alpha']  

# Ініціалізуємо класифікатор Naive Bayes з найкращим alpha  
model = MultinomialNB(alpha=best_alpha)  

# Повторно навчаємо модель з тренувальними даними  
model.fit(X_train, y_train)  

# Робимо прогнози на тестовому наборі  
y_pred = model.predict(X_test)  

# Оцінюємо точність моделі  
accuracy = accuracy_score(y_test, y_pred)  
print(f"Точність після повторного навчання: {accuracy * 100:.2f}%")  

# Виводимо звіт про класифікацію  
print("Звіт про класифікацію:\n", classification_report(y_test, y_pred))  

# Матриця сплутаних класів  
conf_matrix = confusion_matrix(y_test, y_pred)  
sns.heatmap(conf_matrix, annot=True, fmt="d", cmap="Blues", xticklabels=['Ham', 'Spam'], yticklabels=['Ham', 'Spam'])  
plt.xlabel('Прогнозоване')  
plt.ylabel('Правдиве')  
plt.title('Матриця сплутаних класів')  
plt.show()
Точність після повторного навчання: 98.30%  
Звіт про класифікацію:  
 precision recall f1-score support  

 0 0.99 0.99 0.99 954  
 1 0.97 0.91 0.94 161  

 accuracy 0.98 1115  
 macro avg 0.98 0.95 0.96 1115  
weighted avg 0.98 0.98 0.98 1115

pic

Збереження моделі для розгортання

Щоб зробити нашу модель доступною для подальшого використання, ми можемо зберегти її за допомогою joblib. Це дозволить нам завантажити модель і векторизатор пізніше для прогнозів.

# Зберігаємо модель та векторизатор  
joblib.dump(model, 'spam_classifier_model.pkl')  
joblib.dump(vectorizer, 'tfidf_vectorizer.pkl')
# Зберігаємо навчану модель у файл (наприклад, model.joblib)  
joblib.dump(model, 'model.joblib')  

# Зберігаємо векторизатор (якщо використовується) для витягування ознак таким самим чином  
joblib.dump(vectorizer, 'vectorizer.joblib')

Висновок

У цьому пості ми успішно створили простий, але ефективний класифікатор спаму за допомогою технік машинного навчання. Ми охопили всі етапи: від завантаження і підготовки даних, до попередньої обробки тексту, навчання класифікатора наївного баєса та оцінки продуктивності моделі. Також ми дослідили, як налаштування гіперпараметрів може ще більше оптимізувати модель.

Але на цьому веселість не закінчується! Слідкуйте за наступною фазою цього проєкту — розгортанням моделі локально за допомогою Flask і Streamlit для створення інтерактивного досвіду для користувачів. Крім того, ми розглянемо більш складні моделі, такі як BERT і LoRA (Low-Rank Adaptation), які обіцяють ще кращу продуктивність для завдань NLP. Ці моделі також будуть розгорнуті локально, покращуючи загальний досвід.

Дякую за прочитане! Не соромтеся залишати коментарі чи питання нижче, і я із задоволенням обговорю чи уточню будь-яку частину цього процесу.

Це мій другий пост на Medium, і я планую опублікувати щонайменше 100 постів. Будь ласка, поставте лайк, якщо це було корисно!

Я спеціалізуюсь на AI, ML, DL, NLP та LLM, і я відкритий для індивідуальних проєктів. Незалежно від того, чи це пов'язано з індустрією, чи з академічними дослідженнями, я можу допомогти втілити ваші ідеї в реальність.
Давайте співпрацювати і створимо щось неймовірне!

Не соромтеся звертатися до мене на Upwork або Fiverr для будь-яких запитів щодо індивідуальних проєктів.

https://www.upwork.com/freelancers/vamshikrishnak?mp_source=share

[

Vamshi K | Профіль | Fiverr

Я пристрасний дослідник, який здобуває ступінь MS by Research в IIIT Bangalore, після завершення бакалаврату в галузі електроніки та...

www.fiverr.com

](https://www.fiverr.com/vamshikrishn486?source=post_page-----e122b40a9715--------------------------------)

Дякую 😊….

Вамші Крішна Канчарла
Давайте співпрацювати і створимо щось неймовірне!

Не соромтеся звертатися до мене на Upwork або Fiverr для будь-яких запитів щодо індивідуальних проєктів.

https://www.upwork.com/freelancers/vamshikrishnak?mp_source=share

[

Vamshi K | Профіль | Fiverr

Я пристрасний дослідник, який здобуває ступінь MS by Research в IIIT Bangalore, після завершення бакалаврату в галузі електроніки та...

www.fiverr.com

](https://www.fiverr.com/vamshikrishn486?source=post_page-----e122b40a9715--------------------------------)

Дякую 😊….

Вамші Крішна Канчарла

Перекладено з: Spam vs. Ham: Building a Spam Classifier Using Machine Learning and NLP

Leave a Reply

Your email address will not be published. Required fields are marked *