%matplotlib inline
! pip install pymorphy2
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import json
from tqdm import tqdm
from sklearn.metrics import *
import warnings
warnings.filterwarnings("ignore")
Collecting pymorphy2 Downloading pymorphy2-0.9.1-py3-none-any.whl (55 kB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 55.5/55.5 kB 3.2 MB/s eta 0:00:00 Collecting dawg-python>=0.7.1 (from pymorphy2) Downloading DAWG_Python-0.7.2-py2.py3-none-any.whl (11 kB) Collecting pymorphy2-dicts-ru<3.0,>=2.4 (from pymorphy2) Downloading pymorphy2_dicts_ru-2.4.417127.4579844-py2.py3-none-any.whl (8.2 MB) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.2/8.2 MB 59.8 MB/s eta 0:00:0000:0100:01 Requirement already satisfied: docopt>=0.6 in /opt/conda/lib/python3.10/site-packages (from pymorphy2) (0.6.2) Installing collected packages: pymorphy2-dicts-ru, dawg-python, pymorphy2 Successfully installed dawg-python-0.7.2 pymorphy2-0.9.1 pymorphy2-dicts-ru-2.4.417127.4579844
/opt/conda/lib/python3.10/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.23.5 warnings.warn(f"A NumPy version >={np_minversion} and <{np_maxversion}"
Анализ тональности¶
Введение¶
Задача Sentiment Analysis¶
- Сегодня мы познакомимся с основами NLP на примере задачи анализа тональности (Sentiment Analysis) с соревнования Kaggle Competition
- Задача соревнования - построить ML модель, способную различать тональность (позитивная, негативная, нейтральная) новостей
Подготовка данных для модели¶
Подготовим данные для моделирования и предсказания тональности
Для Предобрабоки текста:
- Оставим только слова используя регулярки
- Лемматизируем текстовые токены совместно с
WordPunctTokenizer
- Фильтруем стоп слова
Для пребразования текста в числовое представление воспользуемся методами
BoW
иTF-IDF
Оценим обобщающию способность качества модели используя
train_test_split
иf1_score
на тестовой выборкеДля обучения модели воспользуемя случайным лесом, проверим какой метод работает лучше всего
Загрузка Данных¶
Данные записаны в формате json
. Для его чтения воспользуемся библиотекой json
и методом open
.
import pandas as pd
import nltk
import re
import json
with open('/kaggle/input/khazah-news/train.json', encoding = 'utf-8') as json_file:
data = json.load(json_file)
df = pd.read_json('/kaggle/input/khazah-news/train.json')
df.tail()
text | id | sentiment | |
---|---|---|---|
8258 | Как мы писали еще весной, для увеличения сбыта... | 10312 | positive |
8259 | Но молодой министр национальной экономики Биши... | 10313 | negative |
8260 | \n \nВ ЕНПФ назначен новый председатель правле... | 10314 | neutral |
8261 | В Алматы у отделения банка произошло нападение... | 10315 | negative |
8262 | НПП РК «Атамекен» предлагает создать Националь... | 10316 | neutral |
Метка¶
Посмотрим на содержание и распределение классов в нашей целевой фичи
- Будем решать задачу классификации на 3 класса
Каждый пример для обучения состоит из id, текстового фрагмента новости, и лейбла ('positive', 'negative', 'neutral'
).
Задача - предсказать лейбл
df['sentiment'].unique()
array(['negative', 'positive', 'neutral'], dtype=object)
- Посмотрим на соотношение классов. Видим, что в данных присутсвует сильный дисбаланс.
- Почти половина всех новостей - нейтральные, а негативных новостей меньше всего.
df['sentiment'].value_counts()
neutral 4034 positive 2795 negative 1434 Name: sentiment, dtype: int64
Предобработка данных¶
Прежде, чем перейти к ML, текст необходимо предобработать
Шаг 1. Токенизация и удаление стоп-слов¶
Первый шаг предобработки - разбить текст на единицы, с которыми мы будем работать. Эти юниты называются токенами (tokens), а процесс - токенизация (tokenization). В большинстве случаев в качестве токенов используют слова, но иногда работают с буквами.
Сегодня на вебинаре мы будем работать со словами. Проще всего разбить текст на слова по пробелам (не забывая про пунктуацию).
Шаг 2. Удаляем стоп-слова¶
Стоп-слова – это слова, которые выкидываются из текста при обработке текста. Когда мы применяем машинное обучение к текстам, такие слова могут добавить много шума, поэтому необходимо избавляться от нерелевантных слов.
Стоп-слова это обычно понимают артикли, междометия, союзы и т.д., которые не несут смысловой нагрузки. При этом надо понимать, что не существует универсального списка стоп-слов, все зависит от конкретного случая.
# загружаем список стоп-слов для русского
nltk.download('stopwords')
stop_words = nltk.corpus.stopwords.words('russian')
print(f'Cтоп слова: {len(stop_words)}')
print(stop_words)
[nltk_data] Downloading package stopwords to /usr/share/nltk_data... [nltk_data] Package stopwords is already up-to-date! Cтоп слова: 151 ['и', 'в', 'во', 'не', 'что', 'он', 'на', 'я', 'с', 'со', 'как', 'а', 'то', 'все', 'она', 'так', 'его', 'но', 'да', 'ты', 'к', 'у', 'же', 'вы', 'за', 'бы', 'по', 'только', 'ее', 'мне', 'было', 'вот', 'от', 'меня', 'еще', 'нет', 'о', 'из', 'ему', 'теперь', 'когда', 'даже', 'ну', 'вдруг', 'ли', 'если', 'уже', 'или', 'ни', 'быть', 'был', 'него', 'до', 'вас', 'нибудь', 'опять', 'уж', 'вам', 'ведь', 'там', 'потом', 'себя', 'ничего', 'ей', 'может', 'они', 'тут', 'где', 'есть', 'надо', 'ней', 'для', 'мы', 'тебя', 'их', 'чем', 'была', 'сам', 'чтоб', 'без', 'будто', 'чего', 'раз', 'тоже', 'себе', 'под', 'будет', 'ж', 'тогда', 'кто', 'этот', 'того', 'потому', 'этого', 'какой', 'совсем', 'ним', 'здесь', 'этом', 'один', 'почти', 'мой', 'тем', 'чтобы', 'нее', 'сейчас', 'были', 'куда', 'зачем', 'всех', 'никогда', 'можно', 'при', 'наконец', 'два', 'об', 'другой', 'хоть', 'после', 'над', 'больше', 'тот', 'через', 'эти', 'нас', 'про', 'всего', 'них', 'какая', 'много', 'разве', 'три', 'эту', 'моя', 'впрочем', 'хорошо', 'свою', 'этой', 'перед', 'иногда', 'лучше', 'чуть', 'том', 'нельзя', 'такой', 'им', 'более', 'всегда', 'конечно', 'всю', 'между']
Выбор Токенизатора¶
Инициализируем WordPunctTokenizer
, с помощью которого затем разобьем текст на словаimport re
# Наш токенизатор
word_tokenizer = nltk.WordPunctTokenizer()
tokens = word_tokenizer.tokenize('казнить, нельзя помиловать!!!')
print(tokens)
['казнить', ',', 'нельзя', 'помиловать', '!!!']
Запишем предобработку текста в виде функции
# функция которая находит только слова
def words_only(text):
try:
return " ".join(re.findall(r'[А-Яа-яA-zёЁ-]+',text)).lower()
except:
return ""
words_only('Казнить, нельзя помиловать!!!')
'казнить нельзя помиловать'
Дополняем стоп слова¶
Самим дополним список стоп-слов, слова которые не будут нести тональность
# расширим список стоп-слов, словами, которые являеются стоп-словами в данной задаче
add_stop_words = ['kz', 'казахстан', 'астана', 'казахский', 'алматы', 'ао', 'оао', 'ооо']
months = ['январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь',]
all_stop_words = stop_words + add_stop_words + months
Предобработка текста¶
Прогоняем данные json
через чистку str
, затем токенизируем и убираем стоп слова и числа
def process_data(data):
texts = []
targets = []
# поочередно проходим по всем новостям в списке
for item in tqdm(data):
text_lower = words_only(item['text']) # оставим только слова (str)
tokens = word_tokenizer.tokenize(text_lower) # разбиваем текст на слова (lst of str)
# удаляем пунктуацию и стоп-слова
tokens = [word for word in tokens if (word not in all_stop_words and not word.isnumeric())]
texts.append(tokens) # добавляем в предобработанный список
return texts
# запускаем нашу предобработку
y = [item['sentiment'] for item in data]
texts = process_data(data)
100%|██████████| 8263/8263 [00:08<00:00, 941.30it/s]
# example
i = 1
print("Label: ", y[i])
print("Tokens: ", texts[i])
Label: negative Tokens: ['медики', 'рассказали', 'состоянии', 'пострадавшего', 'мужчины', 'которого', 'совершено', 'нападение', 'возле', 'отделения', 'банка', 'тимирязева', 'прокомментировали', 'tengrinews', 'пресс', '-', 'службе', 'управления', 'здравоохранения', 'места', 'происшествия', 'службу', 'скорой', 'помощи', 'обратились', 'двое', 'человек', 'одному', 'месте', 'оказана', 'медицинская', 'помощь', 'госпитализации', 'отказался', 'второй', 'пациент', 'доставлен', 'больницу', 'скорой', 'неотложной', 'помощи', 'бснп', 'сотрясением', 'головного', 'мозга', 'ушибленной', 'раной', 'головы', 'состояние', 'данный', 'момент', 'оценивается', 'ближе', 'удовлетворительному', 'пока', 'проходит', 'обследование', 'больнице', 'сообщили', 'управлении', 'здравоохранения', 'напомним', 'пересечении', 'улиц', 'тимирязева', 'маркова', 'возле', 'бц', 'алатау', 'гранд', 'произошла', 'стрельба', 'ориентировочно', 'обеденное', 'время', 'здании', 'расположены', 'отделения', 'банков', 'втб', 'сбербанк', 'настоящее', 'время', 'полицейские', 'разыскивают', 'подозреваемых', 'стрельбе', 'факту', 'нападения', 'местном', 'управлении', 'внутренних', 'дел', 'начато', 'досудебное', 'расследование', 'статье', 'ук', 'рк', 'разбой', 'создана', 'специальная', 'следственно', '-', 'оперативная', 'группа', 'числа', 'опытных', 'сотрудников', 'подразделений', 'криминальной', 'полиции', 'настоящий', 'момент', 'проводится', 'комплекс', 'оперативных', 'следственных', 'мероприятий', 'направленных', 'установление', 'личностей', 'нападавших', 'задержание', 'ранее', 'банк', 'втб', 'прокомментировали', 'нападение', 'мужчину', 'данным', 'пресс', '-', 'службы', 'банка', 'отделения', 'банка', 'работают', 'штатном', 'режиме', 'применением', 'усиленных', 'мер', 'безопасности', 'сотрудники', 'полиции', 'работают', 'внутри', 'отделения', 'банка', 'втб', 'место', 'происшествия', 'оцеплено']
Шаг 3 . Нормализация слов¶
- Обычно тексты содержат разные грамматические формы одного и того же слова, а также могут встречаться однокоренные слова.
- Чтобы унифицировать слова в тексте и избавиться от различных форм слова, слова в тексте можно нормализовать.
Существует 2 наиболее известных способа нормализации слов:
- стемминг (stemming)
- лемматизация (лемматизация).
В общих чертах они похоже, но между этими методами есть различия. В зависимости от языка и задачи тот или иной метод может быть предпочтительнее.
Стемминг
(англ. stemming — находить происхождение) — это процесс нахождения основы слова для заданного исходного слова. Основа слова не обязательно совпадает с морфологическим корнем слова и не обязана являться существующим словом в языке. Стемминг – это грубый эвристический процесс, который отрезает «лишнее» от корня слов, часто это приводит к потере словообразовательных суффиксовЛемматизация
приводит все встречающиеся словоформы к одной, нормальной словарной форме. Лемматизация использует словарь и морфологический анализ, чтобы в итоге привести слово к его канонической форме – лемме.
from nltk.stem.snowball import SnowballStemmer
# инициализируем стеммер
stemmer = SnowballStemmer("russian")
Пример стемминга для русского языка
from nltk.stem.snowball import SnowballStemmer
stemmer = SnowballStemmer("english")
text = 'tonight we are listening to a webinar in otus'
stemmed_text = ' '.join([stemmer.stem(x) for x in text.split(' ')])
stemmed_text
'tonight we are listen to a webinar in otus'
# примеры стемминга
i = 1
for aword in texts[i][:10]:
aword_stem = stemmer.stem(aword)
print("Before: %s, After: %s" % (aword, aword_stem))
Before: медики, After: медик Before: рассказали, After: рассказа Before: состоянии, After: состоян Before: пострадавшего, After: пострада Before: мужчины, After: мужчин Before: которого, After: котор Before: совершено, After: соверш Before: нападение, After: нападен Before: возле, After: возл Before: отделения, After: отделен
Stemmer¶
Как пример слушаем, слушать, слущали имеют тот же самый бозовый коренть слуша, соответсвенно при токенизации все эти варианты слов будут иметь одну форму слуша
, что снизит количество слов в словаре
text = 'в этот вечер мы слушаем слушать слушали вебинар по обработке естественного языка в отус'
stemmed_text = ' '.join([stemmer.stem(x) for x in text.split(' ')])
print('Original text:\t',text)
print('Stemmed text:\t',stemmed_text)
Original text: в этот вечер мы слушаем слушать слушали вебинар по обработке естественного языка в отус Stemmed text: в этот вечер мы слуша слуша слуша вебинар по обработк естествен язык в отус
Для английского не так хорого работает стеммер
stemmer = SnowballStemmer("english")
text = 'tonight we listening to a webinar in otus'
stemmed_text = ' '.join([stemmer.stem(x) for x in text.split(' ')])
print('Original text:\t',text)
print('Stemmed text:\t',stemmed_text)
Original text: tonight we listening to a webinar in otus Stemmed text: tonight we listen to a webinar in otus
pymorphy (морфологический оптимизатор)¶
Видно, что для русского языка результат не очень хороший. Попробуем что-нибудь получше
# загружаем библиотеку для лемматизации
import pymorphy2 # Морфологический анализатор
# инициализируем лемматизатор :)
morph = pymorphy2.MorphAnalyzer()
i = 1
for aword in texts[i][:10]:
aword_norm = morph.parse(aword)[0].normal_form
print("Исходное слово: %s\tЛемматизированное: %s" % (aword, aword_norm))
Исходное слово: медики Лемматизированное: медик Исходное слово: рассказали Лемматизированное: рассказать Исходное слово: состоянии Лемматизированное: состояние Исходное слово: пострадавшего Лемматизированное: пострадать Исходное слово: мужчины Лемматизированное: мужчина Исходное слово: которого Лемматизированное: который Исходное слово: совершено Лемматизированное: совершить Исходное слово: нападение Лемматизированное: нападение Исходное слово: возле Лемматизированное: возле Исходное слово: отделения Лемматизированное: отделение
text = 'в этот вечер мы слушаем слушать слушали вебинар по обработке естественного языка в отус'
stemmed_text = ' '.join([morph.parse(x)[0].normal_form for x in text.split(' ')])
print('Оригинальный текст:\t',text)
print('Лемматизированный текст:\t',stemmed_text)
Оригинальный текст: в этот вечер мы слушаем слушать слушали вебинар по обработке естественного языка в отус Лемматизированный текст: в этот вечер мы слушать слушать слушать вебинар по обработка естественный язык в отус
from tqdm import tqdm_notebook
# применяем лемматизацию ко всем текстам
for i in tqdm_notebook(range(len(texts))):
text_lemmatized = [morph.parse(x)[0].normal_form for x in texts[i]] # применяем лемматизацию для каждого слова в тексте
texts[i] = ' '.join(text_lemmatized) # объединяем все слова в одну строку через пробел
0%| | 0/8263 [00:00<?, ?it/s]
texts[0]
'досудебный расследование факт покупка енпф пакет облигация тоо бузгул аурум начать инициатива национальный банк рк сообщить директор департамент защита право потребитель финансовый услуга нацбанк казахстан александр терентьев основание досудебный расследование стать обращение национальный банк письмо ноябрь год обращение национальный банк правоохранительный орган мы этот сделка показаться сомнительный недостаточно корректный поэтому нацбанк ноябрь год обратиться правоохранительный орган это мочь озвучить сегодня идти следствие проводиться проверка сказать терентьев декабрь нацбанк заявить знать стать основание проверка енпф декабрь факт проведение проверка единый накопительный пенсионный фонд подтвердиться пресс - служба национальный банк сообщить проверка проводить операция совершить енпф отношение инвестирование собственный актив также финрегулятор сообщать сделка енпф сумма пять млрд завести уголовный дело нацбанк заверять всё происходить затрагивать пенсионный накопление казахстанец наслать ошибка текст выделить мыший нажать ctrl enter'
Моделирование (BoW)¶
Мешок слов¶
Bag of Words или мешок слов — это модель, представляющая собой неупорядоченный набор слов, входящих в обрабатываемый текст.
Часто модель представляют в виде матрицы, в которой строки соответствуют отдельному тексту, а столбцы — входящие в него слова. Ячейки на пересечении являются числом вхождения данного слова в соответствующий документ. Данная модель удобна тем, что переводит человеческий язык слов в понятный для компьтера язык цифр.
На выходе мы получаем векторное представление содержания каждого документа в корпусе
Поправляем метку¶
sklearn модели (классификаторы) могуть работать с форматорм str
в метках, в любом случае давайте преобразуем их числовое представление
# Функция для кодирования лейблов
def label2num(y):
if y == 'positive':
return 1
if y == 'negative':
return -1
if y == 'neutral':
return 0
encoded_y = [label2num(yy) for yy in y]
Эффективность алгоритма некорректно оценивать на обучающих данных! Это все равно что на контрольной ученику давать задачи, разобранные в классе
- Поэтому мы отложим часть данных для тестирования и оценки качества алгоритма.
- Для этого воспользуемся функцией
train_test_split
и отметимstratify
так как распределение меток не сбалансированны
#train test_split
from sklearn.model_selection import train_test_split
train_texts, test_texts, train_y, test_y = train_test_split(texts, encoded_y,
test_size=0.2,
random_state=42,
stratify = y)
Мешок слов (Подготовка данных)¶
Bag of Words или мешок слов — это модель, представляющая собой неупорядоченный набор слов, входящих в обрабатываемый текст
# Инициализируем векторайзер
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(max_features = 1000)
vectorizer.fit(train_texts)
# Топ-10 слов
vectorizer.get_feature_names_out()[:10]
array(['bank', 'invest', 'kase', 'kazakhstan', 'lada', 'today', 'август', 'авиакомпания', 'авто', 'автомобиль'], dtype=object)
# Подтвердим что max_features сработало
len(vectorizer.get_feature_names_out())
1000
- Обучаем vectorizer на train-данных и сразу преобразем их в вектора с помощью метода
fit_transform
- Также применяем обученный
vectorizer
к данным для тестирования
# Обучаем vectorizer на train-данных и сразу преобразем их в вектора с помощью метода fit_transform
train_X = vectorizer.transform(train_texts)
test_X = vectorizer.transform(test_texts)
train_X.todense().shape
(6610, 1000)
Обучаем Классификатор¶
В качестве классификатора будем использовать Random Forest
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators = 500) # инициализируем модель
clf = clf.fit(train_X, train_y) # обучаем ее на тренировочных данных
pred = clf.predict(test_X) # делаем предсказание для тестовых данных
print('Предсказанные метки: ', pred[0:20], ".....")
print('Истинные метки: ', test_y[0:20], ".....")
Предсказанные метки: [ 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 -1 -1 0 0 0] ..... Истинные метки: [1, 0, 1, 0, 0, -1, 0, 1, 0, 0, 0, -1, -1, 1, -1, -1, -1, 0, 0, 0] .....
# Функция для кодирования лейблов
def num2label(y):
if y == 1:
return 'positive'
if y == -1:
return 'negative'
if y == 0:
return 'neutral'
decoded_pred = [num2label(y) for y in pred]
decoded_test_y = [num2label(y) for y in test_y]
print('Предсказанные метки: ', decoded_pred[0:20], ".....",'\n')
print('Истинные метки: ', decoded_test_y [0:20], ".....")
Предсказанные метки: ['neutral', 'neutral', 'positive', 'neutral', 'neutral', 'negative', 'positive', 'positive', 'positive', 'neutral', 'neutral', 'neutral', 'neutral', 'neutral', 'neutral', 'negative', 'negative', 'neutral', 'neutral', 'neutral'] ..... Истинные метки: ['positive', 'neutral', 'positive', 'neutral', 'neutral', 'negative', 'neutral', 'positive', 'neutral', 'neutral', 'neutral', 'negative', 'negative', 'positive', 'negative', 'negative', 'negative', 'neutral', 'neutral', 'neutral'] .....
Оценка Качества¶
Качество классификатора будем оценивать по метрикам accuracy и f1.
print('Accuracy: ', accuracy_score(test_y, pred))
print('F1: ', f1_score(test_y, pred, average = 'macro'))
Accuracy: 0.6346037507562009 F1: 0.6107372194655939
Пересмотрим Результаты¶
for i in range(10):
print('Истинный лейбл:',decoded_test_y[i])
print('Предсказанный лейбл:',decoded_pred[i])
print('Текст новости: ', train_texts[i][:500]+'...')
print('\n')
Истинный лейбл: positive Предсказанный лейбл: neutral Текст новости: снимок четырёхкратный чемпионка мир шахматы среди ребёнок бибисара асаубаев ria ru шахматистка бибисара асаубаев переехать химки казахстан - подмосковный химки казахстан переехать четырёхкратный чемпионка мир шахматы среди ребёнок бибисара асаубаев сообщить телеканал переезд девушка поддержать губернатор регион андрей воробьёв russian news cn экономический пояс шёлковый путь нурла жол отражать единство казахстанский китайский народ - казахстанский политолог - экономический пояс шёлковый путь нур... Истинный лейбл: neutral Предсказанный лейбл: neutral Текст новости: больший страна - больший семья передача ноябрь... Истинный лейбл: positive Предсказанный лейбл: neutral Текст новости: торжественный гашение марка присутствовать сотрудник группа компания самрука казын который протяжение год трудиться экономический важный отрасль страна церемония гашение произвести сотрудник казпочта казахтелек нак казатомпром аз стан темiр жол сегодня совместно работник телефонный связь железный дорога атомный энергетика выпустить почтовый оборот марка посвятить - летие независимость республика каждый участник торжество посвятить год свой жизнь работа благо родина год независимость наш страна п... Истинный лейбл: neutral Предсказанный лейбл: neutral Текст новости: просмотр бекгали жубан дефицит бензин жанаозен связать задержка поставка топливо атырауский завод пользователь lada пожаловаться дефицит бензин заправка жанаозть житель рассказать четыре заправка работать лишь два который установить ограничение - литр топливо автомобиль ситуация прокомментировать бекгали жубан заместитель руководитель управление предпринимательство торговля мангистауска область фото пользователь сайт lada сообщить автовладелец жанаозть заправка автомобиль вынудить тратить нескол... Истинный лейбл: neutral Предсказанный лейбл: neutral Текст новости: арестовать руководство енпф дать новость являться закрытый доступный платный подписчик также мочь приобрести доступ дать новость цена тенг необходимо пройти авторизация... Истинный лейбл: negative Предсказанный лейбл: neutral Текст новости: кызылорд казинформ - кызылорд получить поддержка рамка программа дама - оптим проект компания ер - бак передавать корреспондент миа казинформ ссылка пресс - служба фонд поддержка предпринимательство дама получение кредит пополнение оборотный средство фортебанка фонд дама предложить компания ер - бак заниматься оптовый розничный торговля металлоизделие - процентный гарантирование компания ер - бак работать год являться один крупный предприятие свой сфера помощь кредитный средство компания получит... Истинный лейбл: neutral Предсказанный лейбл: neutral Текст новости: москва дек риа новость прайма уходить год ознаменоваться российский нефтегазовый отрасль два крупный приватизационный сделка первый год британский вр стать владелец акция роснефть герой сначала крупный российский нефтяной компания купить государство контрольный пакет башнефть затем рамка приватизация собственный акция обрести два новый зарубежный инвестор итог собрать планировать этот два сделка обеспечить поступление бюджет триллион рубль закрывать наш проблема текущий бюджетирование позволять ... Истинный лейбл: positive Предсказанный лейбл: positive Текст новости: казинформ - пресс - служба пассажирский перевозка сообщить подробность чп вокзал - январь территория технический парк станция произойти задымление списать вагон жертва пострадать вагон постройка ноябрь год который технический состояние снятой эксплуатация готовиться утилизация - говориться сообщение средний срок эксплуатация пассажирский вагон составлять год причина случиться выясняться итог служебный расследование быть принять соответствующий мера сообщать компания напомнить - час пульт дчс г п... Истинный лейбл: neutral Предсказанный лейбл: positive Текст новости: лишение олимпийский золото илья ильин оспаривать бесполезно сказать вица - министр культура спорт рк сакен мусайбек кулуар мажилис рк передавать корреспондент вернуть медаль пекин принцип согласный решение международный олимпийский комитет мокнуть который вынести он шок сам шок находиться семья мокнуть весь правило закон согласный оспаривать бесполезно - сказать мусайбек слово вица - министр ведомство глава ведомство арыстанбек мухамедиул тяжело воспринимать новость человек любящий спорт человек... Истинный лейбл: neutral Предсказанный лейбл: neutral Текст новости: бывший заместитель руководитель администрация президент казахстан баглан майлыбаев арестовать данные казахстанский сми конец прошлый неделя хищение млрд тенг млн рубль средство республиканский бюджет действительно арестовать комитет национальный безопасность аналог фсб казахстан распространить сегодня январь официальный сообщение задержание баглан майлыбаев другой бывший сотрудник администрация президент николай галихина произойти январь комитет национальный безопасность республика подозрение не...
Моделирование (TF-IDF)¶
TF-IDF - вектора чуть поумнее (Подготовка данных)¶
TF-IDF (от англ. TF — term frequency, IDF — inverse document frequency) — статистическая мера, используемая для оценки важности слова в контексте документа, являющегося частью коллекции документов или корпуса. Вес некоторого слова пропорционален частоте употребления этого слова в документе и обратно пропорционален частоте употребления слова во всех документах коллекции.
Term Frequency число раз терм $t$ встречается в документе $d$.
$$ TF_{t,d} = term\!\!-\!\!frequency(t, d) $$
Inverse Document Frequency мера того, сколько информации несет данное слово. Иными словами, частотные слова, содержащиеся во всех документах несут мало информации, в то время как слова частотные лишь в ограниченном числе документов содержат большое количество информации об этих документах. IDF - это инверсия частоты, с которой некоторое слово встречается в документах коллекции.
$$ IDF_t = inverse\!\!-\!\!document\!\!-\!\!frequency(t) = \log \frac{N}{DF_t} $$
$N$ - число документов в корпусе.
$DF_t$ - число документов содержащих слово $t$.
$$ TF\!\!-\!\!IDF_{t,d} = TF_{t,d} \times IDF_t $$
TF-IDF оценивает важность слов в корпусе документов.
from sklearn.feature_extraction.text import TfidfVectorizer
vectorizer = TfidfVectorizer(max_features = 1000, norm = None)
vectorizer.fit(train_texts)
vectorizer.get_feature_names_out()[:10]
array(['bank', 'invest', 'kase', 'kazakhstan', 'lada', 'today', 'август', 'авиакомпания', 'авто', 'автомобиль'], dtype=object)
Обучаем Классификатор (TF-IDF)¶
Подготовим данные для обучение и обучаем ее на тренировочных данных, предсказываем на тестовой выборке
# Обучаем TF-IDF на train, а затем применяем к train и test
train_X = vectorizer.fit_transform(train_texts)
test_X = vectorizer.transform(test_texts)
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators = 500) # инициализируем модель
clf = clf.fit(train_X, train_y) # обучаем ее на тренировочных данных
pred = clf.predict(test_X) # делаем предсказание для тестовых данных
Оценка Качества¶
Качество классификатора будем оценивать по метрикам accuracy и f1.
print('Accuracy: ', accuracy_score(test_y, pred))
print('F1: ', f1_score(test_y, pred, average = 'macro'))
Accuracy: 0.6684815486993345 F1: 0.642218515263824
Пересмотрим Результаты¶
for i in range(10):
print('Истинный лейбл:',decoded_test_y[i])
print('Предсказанный лейбл:',decoded_pred[i])
print('Текст новости: ', train_texts[i][:500]+'...')
print('\n')
Истинный лейбл: positive Предсказанный лейбл: neutral Текст новости: снимок четырёхкратный чемпионка мир шахматы среди ребёнок бибисара асаубаев ria ru шахматистка бибисара асаубаев переехать химки казахстан - подмосковный химки казахстан переехать четырёхкратный чемпионка мир шахматы среди ребёнок бибисара асаубаев сообщить телеканал переезд девушка поддержать губернатор регион андрей воробьёв russian news cn экономический пояс шёлковый путь нурла жол отражать единство казахстанский китайский народ - казахстанский политолог - экономический пояс шёлковый путь нур... Истинный лейбл: neutral Предсказанный лейбл: neutral Текст новости: больший страна - больший семья передача ноябрь... Истинный лейбл: positive Предсказанный лейбл: neutral Текст новости: торжественный гашение марка присутствовать сотрудник группа компания самрука казын который протяжение год трудиться экономический важный отрасль страна церемония гашение произвести сотрудник казпочта казахтелек нак казатомпром аз стан темiр жол сегодня совместно работник телефонный связь железный дорога атомный энергетика выпустить почтовый оборот марка посвятить - летие независимость республика каждый участник торжество посвятить год свой жизнь работа благо родина год независимость наш страна п... Истинный лейбл: neutral Предсказанный лейбл: neutral Текст новости: просмотр бекгали жубан дефицит бензин жанаозен связать задержка поставка топливо атырауский завод пользователь lada пожаловаться дефицит бензин заправка жанаозть житель рассказать четыре заправка работать лишь два который установить ограничение - литр топливо автомобиль ситуация прокомментировать бекгали жубан заместитель руководитель управление предпринимательство торговля мангистауска область фото пользователь сайт lada сообщить автовладелец жанаозть заправка автомобиль вынудить тратить нескол... Истинный лейбл: neutral Предсказанный лейбл: neutral Текст новости: арестовать руководство енпф дать новость являться закрытый доступный платный подписчик также мочь приобрести доступ дать новость цена тенг необходимо пройти авторизация... Истинный лейбл: negative Предсказанный лейбл: neutral Текст новости: кызылорд казинформ - кызылорд получить поддержка рамка программа дама - оптим проект компания ер - бак передавать корреспондент миа казинформ ссылка пресс - служба фонд поддержка предпринимательство дама получение кредит пополнение оборотный средство фортебанка фонд дама предложить компания ер - бак заниматься оптовый розничный торговля металлоизделие - процентный гарантирование компания ер - бак работать год являться один крупный предприятие свой сфера помощь кредитный средство компания получит... Истинный лейбл: neutral Предсказанный лейбл: neutral Текст новости: москва дек риа новость прайма уходить год ознаменоваться российский нефтегазовый отрасль два крупный приватизационный сделка первый год британский вр стать владелец акция роснефть герой сначала крупный российский нефтяной компания купить государство контрольный пакет башнефть затем рамка приватизация собственный акция обрести два новый зарубежный инвестор итог собрать планировать этот два сделка обеспечить поступление бюджет триллион рубль закрывать наш проблема текущий бюджетирование позволять ... Истинный лейбл: positive Предсказанный лейбл: positive Текст новости: казинформ - пресс - служба пассажирский перевозка сообщить подробность чп вокзал - январь территория технический парк станция произойти задымление списать вагон жертва пострадать вагон постройка ноябрь год который технический состояние снятой эксплуатация готовиться утилизация - говориться сообщение средний срок эксплуатация пассажирский вагон составлять год причина случиться выясняться итог служебный расследование быть принять соответствующий мера сообщать компания напомнить - час пульт дчс г п... Истинный лейбл: neutral Предсказанный лейбл: positive Текст новости: лишение олимпийский золото илья ильин оспаривать бесполезно сказать вица - министр культура спорт рк сакен мусайбек кулуар мажилис рк передавать корреспондент вернуть медаль пекин принцип согласный решение международный олимпийский комитет мокнуть который вынести он шок сам шок находиться семья мокнуть весь правило закон согласный оспаривать бесполезно - сказать мусайбек слово вица - министр ведомство глава ведомство арыстанбек мухамедиул тяжело воспринимать новость человек любящий спорт человек... Истинный лейбл: neutral Предсказанный лейбл: neutral Текст новости: бывший заместитель руководитель администрация президент казахстан баглан майлыбаев арестовать данные казахстанский сми конец прошлый неделя хищение млрд тенг млн рубль средство республиканский бюджет действительно арестовать комитет национальный безопасность аналог фсб казахстан распространить сегодня январь официальный сообщение задержание баглан майлыбаев другой бывший сотрудник администрация президент николай галихина произойти январь комитет национальный безопасность республика подозрение не...