Похожие кейсы мы уже рассматривали на нашем сайте:
В сегодняшнем кейсе мы использовали библиотеки языка Python, такие как: Selenium, BeautifulSoup. Получилось около 27 тысяч отзывов, начиная с 2018 года. В среднем каждый отзыв занимал 2 абзаца листа А4. В 70 % отзывов была проставлена оценка клиентами, в оставшихся 30% — оценка не была проставлена. Полученные данные, у которых были проставлены оценки, мы решили использовать как исходные данные для построения модели обучения с учителем. Модель в дальнейшем нам нужна была, чтобы определить оценку у оставшихся 30% отзывов.
Проставленные оценки были от 1 до 5, но нам нужно было узнать, каким отзыв являлся по качеству, т. е. положительный он или отрицательный. Использовали логику школьных оценок в России: оценки 1,2 — отрицательные, их преобразовали в 0; оценки 3,4,5 – положительные, их преобразовали в 1. Тем самым задача свелась к бинарной классификации.
dataframe.tail(5)
Рисунок 1
Далее начали экспериментировать с моделью бинарной классификации.
Для первого прохода выбрали метод XGBoost для обучения с учителем. Учителем выступают оценки клиентов. В роли модели текста были взяты векторные представления слов Word2Vec, которые формируются в зависимости от контекста.
Предварительно провели предобработку текста, такую как: лемматизация, удаление стоп-слов, нормализация и его токенизация.
from nltk.tokenize import sent_tokenize
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
def tokenize_ru(x):
tokens = x.lower()
tokens = re.sub(r'[^\w\s]+|[\d]',' ',tokens)
tokens = word_tokenize(tokens)
tokens = [i for i in tokens if (i not in string.punctuation)]
stop_words = stopwords.words('russian')
stop_words.extend(['что', 'это', 'так', 'вот', 'быть', 'как', 'в', '—', '–', 'к', 'на', '...'])
tokens = [i for i in tokens if (i not in stop_words)]
tokens = [i.replace("«", "").replace("»", "") for i in tokens]
return tokens
Перебирали лучшие параметры, используя метод GridSearch.
Оптимальные параметры по точности получились при глубине деревьев 8 (max_depth=8) и количество деревьев (n_estimators=88). По умолчанию в библиотеке XGBoost установлено: n_estimators=100, max_depth=3.
xgb_word2vec = Pipeline([
("word2vec", MeanVect(w2v)),
('model_fitting', xgb)])
xgb_word2vec.fit(X_train2, y_train2)
Рисунок 2
для данных условий Confusion matrix (Матрица Путаницы) следующая:
import seaborn as sns
import matplotlib.pylab as plt
%matplotlib inline
from matplotlib.pylab import rcParams
rcParams['figure.figsize'] = 3, 3
plt.figure(figsize=(2,2))
sns.set(font_scale=1.5)
ax = sns.heatmap((pd.crosstab(y_test2, pred2).apply(lambda r: r/r.sum()*100, axis=0)), cbar=None, annot=True, cmap="Blues")
ax.set_ylabel("")
ax.set_xlabel("")
plt.yticks(rotation=0, size = 15)
plt.xticks(rotation=0, size = 15)
Рисунок 3
Далее пробовали использовать SGDClassifier и для векторов слов TF-IDF.
Ниже приведены различные сочетания вариантов и их Confusion matrix:
1. SGDClassifier + Word2Vec (Рисунок 4).
2. SGDClassifier+ TF-IDF (Рисунок 5).
3. XGBoost+ TF-IDF (Рисунок 6).
Рассчитывается f-mera по формуле f-mera = 2*Precision*Recall/(Precision+Recall), где Precision(точность) и Recall(полнота) вычисляются из Confusion matrix, это гармоническое среднее между точностью и полнотой, для бинарной классификации этого вполне достаточно для оценки точности модели. Лучший результат получился при сочетании SGDClassifier + TF-IDF.
Далее, в уже выбранную модель, с лучшей точностью, подставили неактуальные оцененные отзывы, начиная с 2016 по 2018 годы, которые не участвовали в обучении, чтобы проверить правильность обучения и работы модели, в результате получили f-mera: 0.9326314212969897. Эту модель в дальнейшем можно использовать для классификации отзывов, чтобы не тратить время на поиск вручную отрицательных отзывов.
precision_recall_fscore_support(y_prov, predtest, average='macro')
Дальше использовали модель для оценки оставшихся не оцененных 30 процентов отзывов.
Вывод: Для обработки естественного языка (NLP) из нашего опыта, описанного выше, результаты лучше показала связка быстро сходящегося SGDClassifier с TF-IDF, но в свою очередь ключевая часть успеха лежит в предобработке данных.
На вебинаре 15.07.2020 10-00 мск автор представит практический метод анализа отзывов клиентов с приведением исходного кода и указанием используемых технологий, а также ответит на ваши вопросы. Зарегистрироваться можно по ссылке newtechaudit.ru/onlajn-vebinar-analiz-otzyvov-klientov-razmeshhyonnyh-v-internet
veesot
День добрый.
1. А вы разделяли отзывы на категории(например отзывы на покупки, отзывы на услуги) или использовали иной поход? Непонятно что стоит за вашими словами "векторные представления слов Word2Vec, которые формируются в зависимости от контекста"
2. На мой взгляд это похоже на задачу из разряда sentiment analysis, мне кажется вы скорее пробуете угадать настроение человека нежели то что стоит за текстом. Или я не прав?
3. А есть какая-то более явная интерпретация почему тот или иной отзыв оценен как положительный/или отрицательный?
4. Если всё-таки вы не думаете о представлении интерпретации принятого решения, может стоит поглядеть на нейросети? 27 тысяч отзывов на мой взгляд — это уже немало.
anonymous
1). Скорее это общие фразы, про эмбендинги, суть предложения в том, что слова представили в понятной для компьютера форме.
2). Ну тут я думаю взаимосвязано настроение человека и классификация отзыва на положительные или отрицательный, трудно в гневе написать как все хорошо и всем доволен. Я прекрасно понимаю, что множество тонкостей и мыслей: "а если вот так говорит клиент...?", но общую картину классификации я думаю не нарушит.
3) Ну на валлидационной с 2016 по 2018 годы F-mera была больше 0.9, значит в целом модель построена нормально, смотря как вы хотите интерпретировать… Для тех отзывов которые были без оценок этой модели хватило, для определения.
4) Это знаете как "Все засунуть в нейросети и они все сделают.", но есть ли в этом смысл, если подобное можно сделать базовыми методами, в итоге: SVM+ на веса SGD + Tf-IDF.