Использование метода Bag of words и алгоритма Random Forest для выявления спам-комментариев

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

Что ж, «детектор спам-комментариев YouTube» — отличный способ начать и испачкать руки.

ПРЕДВАРИТЕЛЬНЫЕ ТРЕБОВАНИЯ

› Знание Python
› Знание алгоритма Random Forest и модели Bag of words будет преимуществом.
В любом случае я буду объяснять эти термины по мере продвижения вперед.

НАБОР ДАННЫХ

Набор данных довольно прост, он содержит 2000 комментариев к популярным видео на Youtube. Набор данных отформатирован таким образом, что в каждой строке есть комментарий, за которым следует значение, помеченное как 1 или 0 для спама или не спама.

Набор данных можно скачать с этого сайта

http://archive.ics.uci.edu/ml/datasets/YouTube+Spam+Collection

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

Далее нажмите на второй каталог, т.е. Youtube-Spam-Collection-v1 Извлеките все файлы в папку.

Я рекомендую вам хранить все файлы данных и файл Python (.py или .ipynb) в одной папке, чтобы вам было проще извлекать файлы при написании кода.

Часть кода будет выполняться в Spyder, хотя вы можете выбрать любую IDE по своему выбору, если она поддерживает Python.

Мешок слов

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

Рассмотрите следующие предложения и попытайтесь найти, что делает первую пару фраз похожей на вторую пару:

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

Далее мы создаем больший вектор со всеми уникальными словами в обеих фразах, мы получаем правильное матричное представление. Поскольку каждая строка представляет отдельную фразу, обратите внимание на использование 0, чтобы указать, что фраза не содержит слова:

Если вы хотите иметь набор слов с большим количеством фраз, документов или нам нужно будет собрать все уникальные слова, встречающиеся во всех примерах, и создать огромную матрицу N x M, где N — количество примеров, а M - количество вхождений

Кроме того, есть некоторые моменты, о которых нам нужно позаботиться перед подготовкой модели мешка слов
* Каждое слово в нижнем регистре
* Удаление пунктуации
* Удаление очень распространенных слов (стоп-слов)
* Удалите множественное число (например, bunnies =› bunny)
* Выполните лемматизацию (например, reader =› read, read = read)
* Оставьте только часто встречающиеся слова (например, must появляется в ›10 примеров)
* Запись двоичных значений (1 = присутствует, 0 = отсутствует), а не истинных значений

Более того, если бы мы по-прежнему хотели сократить очень распространенные слова и выделить редкие, нам нужно было бы записывать относительную важность каждого слова, а не его необработанное количество. Это известно как частота терминов, обратная частоте документа (TF-IDF), которая измеряет, насколько часто встречается слово или термин в документе.

Алгоритм случайного леса

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

Вот диаграмма, изображающая ансамблевый метод:

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

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

Подготовка нашего кода

  • Импорт набора данных

Сначала мы импортируем один набор данных. Этот набор данных фактически разделен на четыре разных файла. Наш набор комментариев взят из видео PSY-Gangnam Style:

import matplotlib.pyplot as plt
import pandas as pd
df = pd.read_csv(‘D:\\Machine Learning_Algoritms\\Youtube-Spam-Check\\Youtube01-Psy.csv’, encoding =’latin1')

Теперь, если вы используете Spyder, на вкладке «Обозреватель переменных» вы можете проверить, создана ли переменная «df» и назначена ли она набору данных, подобно тому, как показано на диаграмме ниже:

  • Проверка нулевых значений
##checking for all the null values
df.isnull().sum()

К счастью, пропущенных значений нет, поэтому мы можем продолжить.

  • Ищите распределение категорий в столбцах категорий

Давайте посмотрим, сколько строк в наборе данных является спамом, а сколько нет.

##category distribution
df[‘CLASS’].value_counts()

В результате мы получили 175 и 175 соответственно, что в сумме дает 350 строк в этом файле.

  • Техника мешка слов

В scikit-learn метод мешка слов на самом деле называется «CountVectorizer», что означает подсчет того, сколько раз встречается каждое слово, и помещение их в вектор. Чтобы создать вектор, нам нужно создать объект для «CountVectorizer», а затем одновременно выполнить подгонку и преобразование:

from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer()
dv = vectorizer.fit_transform(df[‘CONTENT’])

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

dv

Всего 350 строк, а значит у нас 350 различных комментариев и 1482 слова.

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

vectorizer.get_feature_names()

Результат, полученный после векторизации, начинается с чисел и заканчивается обычными словами.

  • Перемешивание набора данных

Следующая команда перемешивает набор данных с дробью 100%, добавляя frac=1:

dshuf = df.sample(frac = 1)
  • Разделение набора данных

Мы разделим набор данных на наборы для обучения и тестирования. Предположим, что первые 300 будут для обучения, а последние 50 — для тестирования:

dtrain = dshuf[:300]
dtest = dshuf[300:]
dtrain_att = vectorizer.fit_transform(dtrain[‘CONTENT’])
dtest_att = vectorizer.transform(dtest[‘CONTENT’])
dtrain_label = dtrain[‘CLASS’]
dtest_label = dtest[‘CLASS’]

В предыдущем коде важным шагом является vectorizer.fit_transform(dtrain[‘CONTENT’]). На этом этапе у вас есть тренировочный набор, на котором вы хотите выполнить подходящее преобразование, что означает, что он выучит слова, а также создаст матрицу. Однако для тестового набора мы не выполняем повторное подгоночное преобразование, так как не хотим, чтобы модель запоминала разные слова для тестовых данных.

  • Создание классификатора случайного леса

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

from sklearn.ensemble import RandomForestClassifier
RFC = RandomForestClassifier(n_estimators = 80, random_state = 0)
RFC.fit(dtrain_att, dtrain_label)

RFC.score(dtrain_att, dtrain_label)

Результат оценки составляет 97,33%, это действительно хороший результат.

Выполнение матрицы путаницы для проверки количества правильных ответов:

from sklearn.metrics import confusion_matrix
y_pred = RFC.predict(dtrain_att)
confusion_matrix(y_pred, dtrain_label)

Как видите, у нас всего 292 верных прогноза из 300. Это довольно хорошая точность.

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

  • Перекрестная проверка

Чтобы выполнить перекрестную проверку, мы будем использовать все данные обучения и разделить их на четыре разные группы: 20%, 80% и 20% будут данными тестирования, а 80% будут данными обучения:

from sklearn.model_selection import cross_val_score
scores = cross_val_score(RFC, dtrain_att, dtrain_label, cv=5)
scores.mean()

После выполнения среднего значения результатов, которые мы только что получили, мы получаем точность 88,66%.

  • Загрузка всех наборов данных

Теперь мы загрузим все наборы данных и объединим их.

df = pd.concat([pd.read_csv(‘D:\\Machine Learning_Algoritms\\Youtube-Spam-Check\\Youtube01-Psy.csv’, encoding =’latin1'),
 pd.read_csv(‘D:\\Machine Learning_Algoritms\\Youtube-Spam-Check\\Youtube02-KatyPerry.csv’, encoding =’latin1'),
 pd.read_csv(‘D:\\Machine Learning_Algoritms\\Youtube-Spam-Check\\Youtube03-LMFAO.csv’, encoding =’latin1'),
 pd.read_csv(‘D:\\Machine Learning_Algoritms\\Youtube-Spam-Check\\Youtube04-Eminem.csv’, encoding =’latin1'),
 pd.read_csv(‘D:\\Machine Learning_Algoritms\\Youtube-Spam-Check\\Youtube05-Shakira.csv’, encoding =’latin1')])

Весь набор данных состоит из пяти разных видео с комментариями, что означает, что всего у нас около 2000 строк. Проверив все комментарии, мы заметили, что есть 1005 спам-комментариев и 951 не спам-комментарий, что достаточно близко, чтобы разделить его на четные части:

df[‘CLASS’].value_counts()

Далее мы перемешаем весь набор данных и разделим комментарии и ответы:

dshuf = df.sample(frac=1)
d_content = dshuf[‘CONTENT’]
d_label = dshuf[‘CLASS’]

Здесь нам нужно выполнить пару шагов с «CountVectorizer», за которым следует случайный лес. Для этого мы будем использовать функцию в scikit-learn под названием Pipeline. Pipeline действительно удобен и объединяет два или более шагов, так что все шаги рассматриваются как один. Итак, мы создадим конвейер с набором слов, а затем воспользуемся CountVectorizer, а затем классификатором случайного леса. Затем мы напечатаем конвейер и необходимые шаги:

from sklearn.pipeline import Pipeline,make_pipeline
pl = Pipeline([
 (‘bag of words: ‘, CountVectorizer()),
 (‘Random Forest Classifier:’, RandomForestClassifier())])
make_pipeline(CountVectorizer(), RandomForestClassifier())

Мы можем позволить конвейеру называть каждый шаг отдельно, добавив «CountVectorizer» в наш «RandomForestClassifier», и он назовет их «countvectorizer». и 'случайный классификатор леса'

Как только конвейер создан, вы можете просто назвать его подходящим, и он выполнит все остальное, то есть сначала выполнит подгонку, а затем преобразует с помощью «CountVectorizer», а затем подгонку с помощью « Классификатор RandomForestClassifier'. Это преимущество наличия конвейера:

pl.fit(d_content[:1500],d_label[:1500])

Теперь вы вызываете score, чтобы он знал, что при подсчете очков он прогонит набор слов «CountVectorizer», а затем сделает прогноз с помощью «RandomForestClassifier»:

pl.score(d_content[:1500],d_label[:1500])

Вся эта процедура даст результат около 98,3%. Мы можем предсказать только один пример с конвейером. Например, представьте, что у нас есть новый комментарий после обучения набора данных, и мы хотим знать, только что пользователь набрал этот комментарий или это спам:

pl.predict([“What a nice video”])

Как видите, определил правильно.

pl.predict([“Plz subscribe my channel”])

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

scores = cross_val_score(pl, d_content, d_label, cv=5)
scores.mean()

В этом случае мы находим, что средняя точность составила около 89,3%
Это довольно хорошо. Теперь давайте добавим TF-IDF в нашу модель, чтобы сделать ее более точной.

Если вы не знакомы с TF-IDF, вот краткое описание о нем:

  • TF-IDF

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

Добавление TF-IDF в нашу модель:

from sklearn.feature_extraction.text import TfidfTransformer
pl_2 = make_pipeline(CountVectorizer(), TfidfTransformer(norm=None),
 RandomForestClassifier())

Это будет помещено после ‘CountVectorizer’. После того, как мы произвели подсчеты, мы можем получить оценку TF-IDF для этих подсчетов. Теперь добавим это в пайплайн и выполним еще одну перекрестную проверку с той же точностью:

scores = cross_val_score(pl_2, d_content, d_label, cv=5)
scores.mean()

При добавлении TF-IDF мы получаем точность 95,6% для нашей модели.

Доступна еще одна функция scikit-learn, которая позволяет нам искать все параметры, а затем выясняет, какие параметры являются лучшими:

parameters = {
 ‘countvectorizer__max_features’: (1000, 2000),
 ‘countvectorizer__ngram_range’: ((1, 1), (1, 2)),
 ‘countvectorizer__stop_words’: (‘english’, None),
 ‘tfidftransformer__use_idf’: (True, False), 
 ‘randomforestclassifier__n_estimators’: (10, 30, 50)
 }

Мы можем сделать небольшой словарь, в котором мы произносим имя шага конвейера, а затем упоминаем, каким будет имя параметра, и это дает нам наши варианты. Для демонстрации мы попробуем максимальное количество слов или, может быть, максимум 1000 или 2000 слов. Используя ngrams, мы можем упоминать только отдельные слова или пары слов, которые являются стоп-словами, использовать английский словарь стоп-слов или не использовать стоп-слова, что означает, что в первом случае нам нужно избавиться от общеупотребительных слов. , а во втором случае мы не избавляемся от общеупотребительных слов. Используя TF-IDF, мы используем JEG, чтобы указать, да или нет. Созданный нами случайный лес использует 20, 50 или 100 деревьев. Используя это, мы можем выполнить поиск по сетке, который просматривает все комбинации параметров и определяет наилучшую комбинацию. Итак, давайте дадим наш конвейер номер 2, в котором есть TF-IDF.

Проверить список доступных параметров в grid_search:

grid_search.estimator.get_params()

Мы будем использовать «fit» для выполнения поиска:

grid_search.fit(d_content, d_label)

Поскольку слов много, это занимает немного времени, около 50 секунд (в моем случае), и в конечном итоге находит лучшие параметры. Мы можем получить лучшие параметры из поиска по сетке и распечатать их, чтобы увидеть, какова оценка:

print(“Best accuracy:” , grid_search.best_score_)
print(“Best parameters: “)
best_params = grid_search.best_estimator_.get_params()
for name in sorted(best_params.keys()):
   print(‘{} : {}’.format(name, best_params[name]))

Итак, мы получили почти 96% точности. Мы использовали около 1000 слов, только отдельные слова, использовали «да», чтобы избавиться от стоп-слов, имели 30 деревьев в случайном лесу и использовали «да», IDF и вычисление TF-IDF. Здесь мы продемонстрировали не только пакет слов, TF-IDF и случайный лес, но также функцию конвейера и функцию поиска по параметрам, известную как поиск по сетке.

Если вы хотите посмотреть на другие мои проекты, вот репозиторий GitHub:
https://github.com/AkshayLaddha943