Постановка задачи

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

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

Импорт необходимых библиотек

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn import preprocessing
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, accuracy_score
from sklearn.naive_bayes import MultinomialNB

import nltk
#nltk.download()
from nltk.tokenize import word_tokenize

import warnings
warnings.filterwarnings('ignore')

Чтение набора данных

data = pd.read_csv(os.path.join(dirname, filename))
data.head()

Контекст

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

Содержание

Ниже приведены значения, которые имеет каждый столбец. Имена столбцов говорят сами за себя.

websiteurl: URL-адрес веб-сайта.

очищенныйwebsite_text: очищенный текстовый контент, извлеченный с веб-сайтов.

Категория: целевая функция

Изучение и понимание данных

data.shape
(1408, 4)

В наборе данных 1408 строк и 4 функции.

Удаление безымянного столбца (серийный номер), поскольку он бесполезен, поэтому мы его удаляем.

data = data.drop('Unnamed: 0', axis=1)
data.head()
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1408 entries, 0 to 1407
Data columns (total 3 columns):
 #   Column                Non-Null Count  Dtype 
---  ------                --------------  ----- 
 0   website_url           1408 non-null   object
 1   cleaned_website_text  1408 non-null   object
 2   Category              1408 non-null   object
dtypes: object(3)

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

Подсчет уникальных URL веб-сайтов

data.website_url.nunique()
1384

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

Значение счетчика целевой функции

data.Category.value_counts(dropna=False)
Education                          114
Business/Corporate                 108
Travel                             107
Streaming Services                 104
E-Commerce                         101
Sports                             100
Games                               98
News                                94
Food                                92
Photography                         92
Computers and Technology            91
Health and Fitness                  88
Law and Government                  83
Social Networking and Messaging     80
Adult                               16
Forums                              16
Name: Category, dtype: int64

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

Столбец cleaned_website_text содержит текст контента с веб-сайта. Мы будем использовать этот столбец для разработки функций для нашей модели.

Подготовка данных

Метод разработки матрицы признаков:

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

Следующая часть — присвоить значение функции каждой записи данных. Для присвоения значения функции мы будем использовать метод TF-IDF.

TF-IDF — это метод сравнения релевантности слова какому-либо конкретному документу (в данном случае веб-сайту) из данной группы документов.

Чтобы узнать больше о TF-IDF, посетите эту ссылку https://towardsdatascience.com/tf-idf-for-document-ranking-from-scratch-in-python-on-real-world- набор данных-796d339a4089

TF-IDF=TF(t,d)∗IDF(t,D)

где,

TF(t,d) = (количество t в d)/(количество слов в d)

IDF(t,D)=log(D/(df+1))

t → процентный срок

d → интересующий документ

Д → Комплект документов

df→ появление t в документах

Подводя итог, оценка TF-IDF любой функции для любого конкретного документа будет высокой, если этот термин функции редко встречается в других документах и ​​/ или процент встречаемости этого термина в данном документе выше.

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

Здесь мы будем использовать библиотеку NLTK для токенизации корпуса с каждого веб-сайта и присвоения тега POS каждому слову. Затем мы будем фильтровать только слова с тегом NOUN и обратно преобразовывать их в корпус. Отфильтрованный корпус слов будет для нас бессмысленным, но может повысить производительность нашей модели.

Fфильтрация существительных из корпуса

filtered_words = []
for i in range(data.shape[0]):
    tagged = nltk.pos_tag(word_tokenize(data.cleaned_website_text[i]), tagset='universal')
    filtered_words.append(' '.join([word_tag[0] for word_tag in tagged if word_tag[1]=='NOUN']))

Универсальные части речи теги – это метки частей речи, используемые в проекте Universal Dependencies (UD), который развивается на разных языках. согласованная аннотация банка дерева для многих языков.

Добавление отфильтрованных слов в наш Dataframe

data['filtered_words'] = filtered_words
data.head()

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

  • min_df: при построении словаря игнорируйте термины, частота документирования которых строго ниже заданного порога. В литературе это значение также называют отсечкой. Мы бы использовали 5 как минимальную частоту.
  • стоп-слова: мы удалим английские стоп-слова, если они вообще присутствуют в отфильтрованных словах. Стоп-слова не добавляют смысла модели.
  • max_features: максимальное количество функций, которые будут включены в данные. Мы собираемся использовать 1500 функций.

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

tfidf = TfidfVectorizer(sublinear_tf=True,
                        min_df=5,
                        stop_words = 'english',
                        max_features = 1500)
feat = tfidf.fit_transform(data.filtered_words)
# Feature names

tfidf.get_feature_names()

Преобразование вектора tf-idf в кадр данных

X = pd.DataFrame(feat.toarray(), columns = tfidf.get_feature_names())
X.head()

Кодирование меток и преобразование y

le = preprocessing.LabelEncoder()
y = le.fit_transform(data.Category)
y

Объединение (X и категория) в кадре данных

df_f = pd.concat([X, data.Category], axis=1)
df_f.head()

Групповой график категории

plt.subplots(figsize=(10,15))
for i, col in enumerate(df_f.columns[0:5]):
    plt.subplot(int(df_f.columns[0:5].shape[0]/2)+1, 2, i+1)
    df_f.groupby('Category').mean()[col].plot(kind='barh', title=col)

Наблюдения из приведенного выше сюжета: -

  • Термин аксессуары больше связан с электронной коммерцией.
  • Срок доступа больше связан со стриминговыми сервисами.
  • Термин «способность» больше связан с бизнесом/корпорациями.
  • Термин академия больше связан с законом и правительством.
  • Доступность термина больше связана с Законом и Правительством.

Сплит "поезд-тест"

X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                     train_size = 0.7, 
                                     test_size = 0.3, 
                                     random_state = 100,
                                     stratify = y)

Обучение моделированию и оценка

model = MultinomialNB()
model.fit(X_train, y_train)
y_train_pred = model.predict(X_train)
y_test_pred = model.predict(X_test)

Accuracy check

print('Train accuracy:', round(accuracy_score(y_train, y_train_pred),2))
print('Test accuracy:', round(accuracy_score(y_test, y_test_pred),2))

Точность поезда: 0,93
Точность теста: 0,9

Набор "Матрица путаницы поезда"

plt.subplots(figsize=(12,8))
sns.heatmap(confusion_matrix(y_train, y_train_pred),
           annot=True,
           cmap='YlGnBu')

Матрица путаницы тестового набора

plt.subplots(figsize=(12,8))
sns.heatmap(confusion_matrix(y_test, y_test_pred),
           annot=True,
           cmap='YlGnBu')

Матрица путаницы указывает, что

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

Заключение/рекомендации

  • NLP можно использовать для обработки текста и разработки функций, которые будут использоваться при построении моделей ML.
  • Алгоритм полиномиального наивного Байеса можно использовать для выполнения многоклассовой классификации с большим количеством классов.
  • Наивный Байес в целом может довольно легко обрабатывать большое количество функций по сравнению с размером данных.
  • Для будущей работы мы можем увеличить количество записей данных для классов с меньшей частотой и, следовательно, еще больше улучшить модель.
  • Мы достигли 90% точности теста.

Надеюсь, вам понравился анализ!

Вы можете подписаться на меня в Linkedin, Github и Kaggle.

Ссылка на гитхаб

https://github.com/ratul442

Каггл Ссылка

https://www.kaggle.com/ratul6

LinkedIn Ссылка

https://www.linkedin.com/in/ratul-ghosh-8048a8148/