Автор статьи: Рустем Галиев

IBM Senior DevOps Engineer & Integration Architect

Привет Хабр! В прошлой статье мы векторизировали данные, теперь нам осталось написать модель и протестировать её

Мы построим модель для обнаружения спам-сообщений с использованием алгоритма случайного леса. Случайный лес — это очень мощный алгоритм, который очень широко используется. Мы не будем углубляться в математику алгоритма случайного леса, а воспользуемся его реализацией в библиотеке Scikit-Learn.

Мы создаем модель с использованием алгоритма случайного леса.

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

Алгоритм случайного леса разбивает набор данных на подмножества строк и столбцов. В каждом из подмножеств алгоритм случайного леса создает деревья решений на основе данных. Каждое дерево решений делает прогноз. Затем он собирает все прогнозы и принимает решение, наиболее популярное среди деревьев решений на подмножествах данных. Теперь, чтобы сделать отдельные деревья решений, алгоритм дерева решений будет уделять больше внимания функциям, которые могут быть более важными. Ради справки, вы можете понять, что дерево решений будет разбивать набор данных, чтобы принимать решения на основе того, насколько примеси уменьшаются в наборе данных.

Ранее мы начали с набора содержимого SMS и связанных с ним меток, чтобы определить, является ли SMS доброкачественным или спамом. Из содержимого SMS мы определили количество URL-адресов в содержимом и количество мобильных номеров в содержимом. Это дало нам 2 функции. Затем мы преобразовали очищенный текст из содержимого в матрицу TF-IDF. Итак, теперь у нас есть обучающий набор данных, который имеет 5104 точки данных, и каждая точка данных имеет 7936 признаков. Кроме того, у нас есть 4334 точки данных для безопасных SMS-сообщений и 680 точек данных для спам-сообщений.

Примечание. Когда мы создавали матрицу TF-IDF в предыдущей лабораторной работе, мы установили ngram_range в диапазоне от 1 до 4. Это создало более 80 000 функций. Здесь для ngram_range установлено значение от 1 до 1. Это сделано для того, чтобы модель помещалась в память, доступную на этой небольшой машине. Если вы работаете на более крупной машине, вы можете попробовать увеличить диапазон ngram_range.

Открываем файл, в который будем писать код:

spamSMSDetection.py

И наш код:

import createTFIDF
import os

_, _, X_train, X_test, y_train, y_test = createTFIDF.createTFIDF()
os.system('clear')

from   sklearn.ensemble import RandomForestClassifier

rf = RandomForestClassifier()
rf.fit(X_train, y_train)

import pandas as pd
df = pd.DataFrame(columns = ['Feature', 'FeatureImportance'])
df['Feature'] = X_train.columns
df['FeatureImportance'] = rf.feature_importances_
print('Importance of the Features in the Model\n\n', df.sort_values(by = 'FeatureImportance', ascending = False))

Прогоним его

python3 spamSMSDetection.py

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

Тестируем модель на тренировочном датасте

На предыдущем шаге мы создали нашу модель для обнаружения спам-сообщений с использованием алгоритма случайного леса. Теперь мы будем делать прогнозы по обучающему набору данных, используя созданную нами модель. Делая прогнозы в наборе обучающих данных, мы можем сравнить прогнозы с фактической меткой, доступной нам для каждого SMS в наборе обучающих данных, предоставленной экспертами. Это сравнение покажет нам, насколько хороша наша модель. Мы проверим, сколько прогнозов модель сделала правильно, и это даст нам точность модели. Мы также создадим матрицу путаницы(confusion matrix), которая покажет нам, в скольких случаях модель предсказала правильно, а в скольких — нет.

from   sklearn.metrics import confusion_matrix
from   sklearn import metrics
import pandas as pd

os.system('clear')

yTrainPred = rf.predict(X_train)

confusionMatrix = confusion_matrix(y_train, yTrainPred, labels = rf.classes_)
c = pd.DataFrame(confusionMatrix, columns = rf.classes_)
c.index = rf.classes_
print('Confusion Matrix\n\n', c)
print("\n\nTraining Accuracy = %5.5f%s" % (metrics.accuracy_score(y_train, yTrainPred) * 100, "%"))

python3 spamSMSDetection.py

Обратите внимание, что точность модели составляет 99.98006%.

В матрице путаницы обратите внимание на следующее:

  • В 4334 случаях ССМ были действительно доброкачественными, и модель также предсказывала, что они были доброкачественными. Это так называемые истинные плюсы.

  • В 679 случаях SMS на самом деле были спамом, и модель также предсказывала, что они были спамом. Это так называемые истинные негативы.

  • В 1 случаях SMS были на самом деле безопасными, и модель предсказывала, что они были спамом. Это так называемые ложные срабатывания.

  • В 1 случаях SMS на самом деле были SMS-спамом, и модель предсказывала, что они были безопасными. Они называются ложноотрицательными.

Теперь к тестированию!

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

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

Начнем с тестирования модели на тестовых данных. Однако, прежде чем мы сможем применить модель для прогнозирования тестовых данных, мы должны предварительно обработать тестовые данные так же, как мы предварительно обработали обучающие данные. Получив предварительно обработанные данные, мы можем применить модель.

import os
import createModel

rf, tfidf, le, X_train, X_test, y_train, y_test = createModel.createModel()
os.system('clear')

import pandas as pd

tfidfText = tfidf.transform(X_test.cText)
dfTFIDF = pd.DataFrame(tfidfText.todense(), columns = tfidf.get_feature_names_out())

X_test_temp = dfTFIDF
X_test_temp['noURLs'] = X_test['noURLs']
X_test_temp['noMobiles'] = X_test['noMobiles']
X_test_temp['noURLs'] = X_test_temp['noURLs'].fillna(0)
X_test_temp['noMobiles'] = X_test_temp['noMobiles'].fillna(0)

X_test = X_test_temp

yTestPred = rf.predict(X_test)

from   sklearn.metrics import confusion_matrix

os.system('clear')

confusionMatrix = confusion_matrix(y_test, yTestPred, labels = rf.classes_)
c = pd.DataFrame(confusionMatrix, columns = rf.classes_)
c.index = rf.classes_
print('Confusion Matrix\n\n', c)

from   sklearn import metrics
print("\n\nTest Accuracy = %5.5f%s" % (metrics.accuracy_score(y_test, yTestPred) * 100, '%'))

Запустим

Обратите внимание, что точность модели на тестовых данных составляет 98,38710%.

В матрице путаницы обратите внимание на следующее:

  • В 491 случае SMS действительно были доброкачественными, и модель также предсказывала, что они были доброкачественными. Это так называемые истинные плюсы.

  • В 58 случаях SMS на самом деле были спамом, и модель также предсказывала, что они были спамом. Это так называемые истинные негативы.

  • В 1 случае SMS были на самом деле безопасными, и модель предсказывала, что они были спамом. Это так называемые ложные срабатывания.

  • В 9 случаях SMS на самом деле были спамом, и модель предсказывала, что они были безопасными. Они называются ложноотрицательными.

Тест 1 на данных, близких к реальному времени

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

import cleanData
import extractFeatures
import pandas as pd

os.system('clear')

testSMS = "This is a test SMS to be checked for spam"

text = extractFeatures.extractFeatures(testSMS)[0]
noURLs = extractFeatures.extractFeatures(testSMS)[1]
noMobiles = extractFeatures.extractFeatures(testSMS)[2]

cText = cleanData.cleanData(text)

tfidfText = tfidf.transform([cText])
dfTFIDF = pd.DataFrame(tfidfText.todense(), columns = tfidf.get_feature_names_out())

X = dfTFIDF
X['noURLs'] = noURLs
X['noMobiles'] = noMobiles
X['noURLs'] = X['noURLs'].fillna(0)
X['noMobiles'] = X['noMobiles'].fillna(0)

prediction = rf.predict(X)
print('The input SMS =', testSMS)
print('\nThe prediction by the model = ', le.inverse_transform(prediction))

Запускаем

Обратите внимание, что наша модель предсказывает, что входная SMS-сообщение является доброкачественной. Обратите внимание, что в нашем наборе данных SMS со спамом помечены как спам, а безопасные SMS помечены как “ham”.

Тест 2 на данных, близких к реальному времени

Теперь мы выполним последний тест данных, которые мы создадим. Мы увидим, идентифицирует ли модель это как спам или ham. Обратите внимание, что модель можно улучшить, если ее развернуть на машине с большим объемом памяти. Прямо сейчас мы сократили количество функций примерно до 5000, установив для ngram_range значение (1, 1). Модель работала бы намного лучше, если бы мы могли установить ngram_range = (1, 4). Кроме того, из-за нехватки памяти мы не могли сбалансировать набор данных и не могли применить анализ основных компонентов (PCA), чтобы ограничиться только наиболее важными функциями.

import cleanData
import extractFeatures
import pandas as pd

os.system('clear')

testSMS = "You won the lottery. Click this link http://fake.com or call 9988776655 as soon as possible"

text = extractFeatures.extractFeatures(testSMS)[0]
noURLs = extractFeatures.extractFeatures(testSMS)[1]
noMobiles = extractFeatures.extractFeatures(testSMS)[2]

cText = cleanData.cleanData(text)

tfidfText = tfidf.transform([cText])
dfTFIDF = pd.DataFrame(tfidfText.todense(), columns = tfidf.get_feature_names_out())

X = dfTFIDF
X['noURLs'] = noURLs
X['noMobiles'] = noMobiles
X['noURLs'] = X['noURLs'].fillna(0)
X['noMobiles'] = X['noMobiles'].fillna(0)

prediction = rf.predict(X)
print('The input SMS =', testSMS)
print('\nThe prediction by the model = ', le.inverse_transform(prediction))

Запустим его

Написали, протестировали и Вы восхитительны!

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

Комментарии (4)


  1. ifap
    00.00.0000 00:00

    А где использовать эту модель?


    1. imageman
      00.00.0000 00:00

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


      1. ifap
        00.00.0000 00:00

        Я про другое: допустим, оператор захочет внедрить у себя эту (или аналогичную) систему, но его юрист будет слегка против, т.к. закон "О связи" и подзаконные НПА велят операторам оной доставлять сообщения электросвязи до адресатов (абонентов), не решая за них, что есть спам, а что - долгожданное письмецо от тетушки из Бразилии. Операторы электропочты элегантно решили проблему папкой "Спам", куда они все равно доставляют сомнительное сообщение, лишь высказывая свое мнение о его некошерности (хотя некоторые ходят по тонкому льду, применяя всякие RBL), а SMS либо доставляются абоненту, либо нет...


        1. imageman
          00.00.0000 00:00

          Есть и другие места, где можно применить такую систему: форумы, комментарии пользователей, соцсети, общение в играх и т.п.