Создайте свою первую модель машинного обучения для фильтрации спама

Tags: machine learning, ИИ, AI

Создание спам-фильтра с помощью машинного обучения

Редакционное примечание

Эта статья представляет собой запись в нашем решении по компьютерному обучению и искусственному интеллекту. Статьи в этом подразделе не обязательно должны быть полными статьями, поэтому при голосовании следует соблюдать осторожность.

Введение

Машинное обучение позволяет нам  использовать математику и статистические вероятности на основе данных для определения исходного кода. Это позволяет нам создавать код, который «развивается» с течением времени, поскольку он основан на изменениях данных, а не на конкретных жестко закодированных значениях или  хранящихся где-то конкретных значениях.

Например, использование клиентом своей кредитной карты с течением времени изменяется и развивается на основе их привычек покупки, и компания карты должна продолжать определять мошеннические транзакции. Если в коде или в базе данных задан «порог», то значение будет периодически обновляться, и определение того, каково должно быть это значение, было бы дорого или сложно для большого числа клиентов. Периодически обучение модели машинного обучения для выявления мошеннических действий на основе фактических данных гораздо более удобно.

Для этой статьи мы будем использовать «контролируемое обучение», чтобы определить, является ли сообщение «spam’ом» или «ham’ом» (спам-сообщение электронной почты или сообщение электронной почты, не относящееся к спаму). Контролируемое обучение означает, что у нас есть набор данных, который содержит сообщения, которые уже были идентифицированы как «spam» или «ham», и мы будем использовать эти данные для обучения модели машинного обучения, чтобы иметь возможность идентифицировать новые сообщения как спамовые и неспамовые. Это определение основано на статистическом сходстве новых сообщений с сообщениями, на которых мы обучали модель.

Бэкграунд

Если у вас есть достойный уровень знания программирования и интерес к компьютерному обучению, вы должны следовать этому руководству. Данные, предоставленные CodeProject, выглядят следующим образом:

# Spam training data

Spam,<p>But could then once pomp to nor that glee glorious of deigned. The vexed times childe none native.

To he vast now in to sore nor flow and most fabled. The few tis to loved vexed and all yet yea childe.

Fulness consecrate of it before his a a a that.</p><p>Mirthful and and pangs wrong. Objects isle with

partings ancient made was are. Childe and gild of all had to and ofttimes made soon from to long youth

way condole sore.</p>

Spam,<p>His honeyed and land vile are so and native from ah to ah it like flash in not. That gild by

in basked they lemans passed way who talethis forgot deigned nor friends his before strange. Found long

little the. Talethis have soon of hellas had

Начальное значение, обозначающее "Spam" или "Ham", за которым следует тэг  <p>, а затем содержимое сообщения. Кроме того, файл разделен на разделы обучения и тестирования (подробнее об этом ниже).

Импорт библиотек

Здесь, как и во многих языках, мы импортируем различные библиотеки, которые нам понадобятся для нашего кода. Далее мы подробно рассмотрим, что используем.

import pandas as pd

import numpy as np

 

from sklearn.feature_extraction.text import TfidfVectorizer

from sklearn.feature_extraction.text import CountVectorizer

from sklearn.pipeline import FeatureUnion

 

from sklearn.linear_model.logistic import LogisticRegression

from sklearn.ensemble import RandomForestClassifier

from sklearn.svm import LinearSVC

from sklearn.tree import DecisionTreeClassifier

 

from sklearn.utils import shuffle

from sklearn.metrics import precision_score, classification_report, accuracy_score

 

import time

Загрузка и анализ данных

Несмотря на то, что работа ученым по данным - самая привлекательная работа 21 века, требуется много времени, чтобы выполнять непривлекательный процесс анализа, очистки, понимания данных, с которыми вы работаете. Для этого проекта, вероятно, 85% моего времени было потрачено именно на это.

def get_data():

   file_name = './SpamDetectionData.txt'

   rawdata = open(file_name, 'r')

   lines = rawdata.readlines()

   lines = lines[1:] #get rid of "header"

   spam_train = lines[0:1000]

   ham_train = lines[1002:2002]

   test_mix = lines[2004:]

   return (spam_train, ham_train, test_mix)

В функции get_data () мы получаем данные обучения и тестирования из файла, предоставленного CodeProject. Мы читаем необработанные данные из файла и храним их в массиве. В строках типа:

 spam_train = lines[0:1000]

 ham_train = lines[1002:2002]

 test_mix = lines[2004:]

мы просто разбиваем части массива на отдельные массивы со значимыми именами. Подробнее о том, как и почему мы тестируем и обучаем данные, будет описано ниже/

Создание Pandas DataFrame

Для подавляющего большинства проектирования данных и функций, которое вы будете осуществлять в компьютерном обучении, вы будете использовать Pandas, поскольку он предоставляет очень мощный (хотя и иногда запутанный) массив инструментов для работы с данными. Здесь мы создаем DataFrame, который проще всего воспринимать как «таблицу» в памяти, содержащую строки и столбцы, где один столбец содержит содержимое сообщения spam / ham, а другой столбец содержит двоичный флаг (или категорию в лингвистике данных), указывающий, является ли сообщение «spam’ом» (1) или «ham’ом» (0).

def create_dataframe(input_array):    

   spam_indcator = 'Spam,<p>'

   message_class = np.array([1 if spam_indcator in item else 0 for item in input_array])

   data = pd.DataFrame()

   data['class'] = message_class

   data['message'] = input_array

   return data

Вот как выглядит наш кадр данных, прежде чем мы очистим его на следующем шаге - включая только что добавленный столбец класса.

DataFrame перед очисткой данных:



Удаление слов и перетасовка данных

Здесь, основываясь на том, что я видел в данных, мы будем удалять любой посторонний текст, который ничего не значит, например <p>, или, в данном случае - очевидные данные, которые служат для указания типа сообщения, например «Ham, <p>», которое не будет в реальных сообщениях, которые мы будем пытаться классифицировать. Когда мы их найдем, мы просто заменим их на пустую строку.

words_to_remove = ['Ham,<p>', 'Spam,<p>', '<p>', '</p>', '\n']

 

def remove_words(input_line, key_words=words_to_remove):

   temp = input_line

   for word in key_words:

       temp = temp.replace(word, '')

   return temp

Здесь мы применяем фильтрацию над нашим кадром данных и затем перетасовываем данные. Несмотря на то, что перетасовка не требуется для данных, предоставленных CodeProject, поскольку она уже разделена на группы данных обучения и тестовых данных, если вы выполняли этот процесс в другом наборе данных, вы всегда хотели бы перетасовать данные, прежде чем разделять их на обучение и тестовые наборы, чтобы обеспечить примерно одинаковое количество примеров в каждом наборе (в данном случае спам и неспам). Если эти наборы не сбалансированы, они могут легко привести к смещению в процессе обучения или тестирования.

def remove_words_and_shuffle(input_dataframe, input_random_state=7):

   input_dataframe['message'] = input_dataframe['message'].apply(remove_words)

   messages, classes = shuffle(input_dataframe['message'], input_dataframe['class'], random_state=input_random_state)

   df_return = pd.DataFrame()

   df_return['class'] = classes

   df_return['message'] = messages

   return df_return

Вот наш кадр данных после его очистки:


Обучение и тестирование наших моделей

Это то, о чем мы и говорим здесь, - использование тренировочных данных для обучения нашей модели машинного обучения, а затем использование тестовых данных для определения точности модели и того, насколько хорошо она реализуется

def test_models(X_train_input_raw, y_train_input, X_test_input_raw, y_test_input, models_dict):

 

   return_trained_models = {}

   

   return_vectorizer = FeatureUnion([('tfidf_vect', TfidfVectorizer())])

   

   X_train = return_vectorizer.fit_transform(X_train_input_raw)

   X_test = return_vectorizer.transform(X_test_input_raw)

   

   for key in models_dict:

       model_name = key

       model = models_dict[key]

       t1 = time.time()

       model.fit(X_train, y_train_input)

       t2 = time.time()

       predicted_y = model.predict(X_test)

       t3 = time.time()

       

       output_accuracy(y_test_input, predicted_y, model_name, t2 - t1, t3 - t2)        

       return_trained_models[model_name] = model

       

   return (return_trained_models, return_vectorizer)

В этом коде много чего происходит, поэтому мы пройдем его по строкам. Во-первых, давайте посмотрим на параметры:

 

X_train_input_data - это «сырые» сообщения о спаме / неспаме, которые мы будем использовать для обучения модели

y_train_input - это 0 или 1 для обозначения ham или spam  для параметра X_train_input_data

X_test_input_raw - «сырые» сообщения о спаме / неспаме, которые мы будем использовать для проверки точности обучаемой модели

y_test_input - 0 или 1 для обозначения ham или spam для параметра X_test_input_raw

return_trained_models = {} - словарь, который будет содержать подготовленные нами модели, чтобы их можно было использовать позже

 

return_vectorizer = FeatureUnion ([(tfidf_vect), TfidfVectorizer ())]) устанавливает TfidfVectorizer для применения к сообщениям. По существу, то, что мы делаем, превращает строку слов (сообщение) в вектор (массив) количества вхождений этих слов.

Кроме того, TF-IDF (текстовая частота-обратная частота документа) применяет вес к частоте, с которой термин присутствует в исходном документе.

“Значение tf - idf увеличивается пропорционально количеству раз, которое слово появляется в документе и компенсируется частотой слова в корпусе, что помогает приспособиться к тому, что некоторые слова  в целом появляются чаще. В настоящее время tf-idf является одной из самых популярных схем взвешивания по срокам; 83% текстовых рекомендательных систем в области цифровых библиотек используют tf - idf” (Wiki)

Это означает, что те термины, которые появляются в целом реже, но чаще в конкретном типе документа, будут иметь больший вес. Например, слова «бесплатно», «виагра» и т. д., которые не отображаются очень часто в сообщениях в целом (все сообщения для спама и неспама объединены), но очень часто появляются в сообщениях со спамом, поэтому эти слова будут весить больше, чтобы указать, что документ является спамом.

Существует очень большой набор параметров, которые можно установить и настроить для повышения точности модели.

Далее, теперь, когда мы создали наш векторизатор, мы будем «обучать» его на тренировочных сообщениях и использовать его для преобразования нашего набора тестовых сообщений в векторы:

 

X_train = return_vectorizer.fit_transform (X_train_input_raw)

 

X_test = return_vectorizer.transform (X_test_input_raw)

Заключительный шаг - перебрать словарь моделей, которые были переданы для обучения каждой модели, использовать модель для прогнозирования тестовых данных и вывести точность каждой модели.

Вывод результатов обучения наших моделей

Когда мы готовим наши модели, мы хотим увидеть название модели, сколько времени потребовалось для обучения модели и насколько точна модель. Вот функция, которая помогает в этом:

def output_accuracy(actual_y, predicted_y, model_name, train_time, predict_time):

   print('Model Name: ' + model_name)

   print('Train time: ', round(train_time, 2))

   print('Predict time: ', round(predict_time, 2))

   print('Model Accuracy: {:.4f}'.format(accuracy_score(actual_y, predicted_y)))

   print('Model Precision: {:.4f}'.format(precision_score(actual_y, predicted_y)))

   print('')

   print(classification_report(actual_y, predicted_y, digits=4))

   print("=========================================================================")

Создание нашего словаря моделей для тестирования

Здесь мы создаем словарь моделей, которые мы хотим обучать и точность которых мы хотим проверять. Здесь вы можете добавить больше моделей для тестирования, удалить малоэффективные модели  или изменить параметры моделей, чтобы определить, какая модель лучше всего соответствует вашим потребностям.

def create_models():

   models = {}

   models['LinearSVC'] = LinearSVC()

   models['LogisticRegression'] = LogisticRegression()

   models['RandomForestClassifier'] = RandomForestClassifier()

   models['DecisionTreeClassifier'] = DecisionTreeClassifier()

   return models

Соберем все вместе

Итак, давайте объединим все шаги:

  1. Получение данных и создание кадров данных
  2. Очищение и перетасовка данных
  3. Разделение данных на вход (X) и вывод (y) для обоих обучающих и тестовых наборов
  4. Создание моделей
  5. Передача моделей и данных в функцию test_models () для отображения их производительности

spam_train, ham_train, test_mix = get_data()

 

words_to_remove = ['Ham,<p>', 'Spam,<p>', '<p>', '</p>', '\n']

 

df_train_cleaned = remove_words_and_shuffle(df_train)

df_test_cleaned = remove_words_and_shuffle(df_test)

 

X_train_raw = df_train_cleaned['message']

y_train = df_train_cleaned['class']

 

X_test_raw = df_test_cleaned['message']

y_test = df_test_cleaned['class']

 

X_test_raw = df_test_cleaned['message']

y_test = df_test_cleaned['class']

 

models = create_models()

 

trained_models, fitted_vectorizer = test_models(X_train_raw, y_train, X_test_raw, y_test, models)

Выводимые данные

При запуске мы получим следующее:

 

Model Name: LinearSVC

Train time:  0.01

Predict time:  0.0

Model Accuracy: 1.0000

Model Precision: 1.0000

 

            precision recall  f1-score support

 

         0 1.0000    1.0000 1.0000        57

         1 1.0000    1.0000 1.0000        43

 

avg / total     1.0000 1.0000    1.0000 100

 

======================================================

Model Name: LogisticRegression

Train time:  0.01

Predict time:  0.0

Model Accuracy: 0.4300

Model Precision: 0.4300

 

            precision recall  f1-score support

 

         0 0.0000    0.0000 0.0000        57

         1 0.4300    1.0000 0.6014        43

 

avg / total     0.1849 0.4300    0.2586 100

 

======================================================

Model Name: DecisionTreeClassifier

Train time:  0.02

Predict time:  0.0

Model Accuracy: 0.9800

Model Precision: 0.9556

 

            precision recall  f1-score support

 

         0 1.0000    0.9649 0.9821        57

         1 0.9556    1.0000 0.9773        43

 

avg / total     0.9809 0.9800    0.9800 100

 

======================================================

Model Name: RandomForestClassifier

Train time:  0.02

Predict time:  0.0

Model Accuracy: 0.9800

Model Precision: 0.9556

 

            precision recall  f1-score support

 

         0 1.0000    0.9649 0.9821        57

         1 0.9556    1.0000 0.9773        43

 

avg / total     0.9809 0.9800    0.9800 100

 

======================================================

Мы можем видеть, сколько времени потребовалось для обучения модели, сколько для прогнозирования тестовых данных, а также степень правильности, прецизионности и полноты возврата каждой модели. Некоторые из этих условий требуют дальнейшего объяснения:

  • Правильность - отношение правильно предсказанных наблюдений к общему числу наблюдений (в данном случае, какой процент сообщений о спаме / неспаме был правильно обнаружен)
  • Прецизионность - отношение правильно предсказанных положительных наблюдений к общим прогнозируемым позитивным наблюдениям (сколько из сообщений, которые мы идентифицировали как спам, были идентифицированы правильно)
  • Полнота возврата - отношение правильно предсказанных положительных наблюдений ко всем наблюдениям фактического класса (сколько мы правильно идентифицировали из всех сообщений, которые на самом деле являются спамом)
  • F1 Score - взвешенное среднее значение прецизионности и полноты возврата

Да, это некоторые замысловатые концепции для понимания, а объяснить их еще сложнее.

Попробуйте модель на своем собственном сообщении

Наконец, давайте попробуем наши собственные сообщения, чтобы узнать, правильно ли они определены как spam или ham

#from the sample ham and spam

ham = 'door beguiling cushions did. Evermore from raven from is beak shall name'

spam = 'The vexed times childe none native'

test_messages = [spam, ham]

transformed_test_messages = fitted_vectorizer.transform(test_messages)

trained_models['DecisionTreeClassifier'].predict(transformed_test_messages)

Вот выводимые данные:

array([1, 0])

Что правильно идентифицирует сообщения спама и неспама.

Вывод

Машинное, глубокое обучение и искусственный интеллект - это будущее, и мы, как разработчики программного обеспечения, должны понимать и использовать силу, предлагаемую этими технологиями, поскольку мы можем использовать их для более эффективного решения проблем компаний и клиентов, с которыми мы работаем, чтобы они обращались к нам за помощью.



No Comments

Add a Comment