У цьому блозі я проведу вас через просту, але захоплюючу подорож зі створення системи виявлення спаму за допомогою машинного навчання. Завдання, яке ми вирішуємо, полягає в класифікації 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()
# знайдемо довжину повідомлень
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()
# знайдемо довжину повідомлень
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
Налаштування гіперпараметрів за допомогою 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
Налаштування гіперпараметрів за допомогою 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
Збереження моделі для розгортання
Щоб зробити нашу модель доступною для подальшого використання, ми можемо зберегти її за допомогою 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
Збереження моделі для розгортання
Щоб зробити нашу модель доступною для подальшого використання, ми можемо зберегти її за допомогою 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