Постановка задачи
Целью этого упражнения является классификация веб-сайтов на основе их содержания. Здесь у нас есть набор данных, который содержит список веб-сайтов, их вид и текстовую выдержку из них.
Здесь мы будем использовать методы обработки естественного языка для разработки набора данных, а затем создадим на его основе наивную байесовскую модель для классификации веб-сайтов.
Импорт необходимых библиотек
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% точности теста.
Надеюсь, вам понравился анализ!