предисловие
В этой статье используется алгоритм наивного Байеса для проведения анализа настроений и прогнозирования рецензий на фильмы Douban Top 250.
В последнее время я узнаю об обработке положительных и отрицательных эмоций на естественном языке, но большинство практик, которые можно найти, — это анализ настроений в обзорах фильмов IMDB на Kggle.
Итак, здесь я использую самый простой алгоритм Наивного Байеса для анализа и прогнозирования обзоров фильмов Дубана.
Здесь я имею в видуGitHub.com/AE бомба и это зло/IM…,Большое спасибо.
Наивный байесовский классификатор
Байесовская классификация — это общий термин для класса алгоритмов классификации, основанных на теореме Байеса, поэтому они вместе называются байесовской классификацией.
Этот алгоритм часто используется для классификации статей, спама и спам-комментариев.Наивный Байес имеет хороший эффект и низкую стоимость.
Зная некоторую условную вероятность, как получить вероятность после обмена двумя событиями, то есть как получить P(B|A), когда известно P(A|B).
P(B|A) представляет собой вероятность того, что событие B произойдет при условии, что произошло событие A, которая называется условной вероятностью события B при наступлении события A.
Формула наивного Байеса
Простой в использовании видеоурок
Youtube Woohoo.YouTube.com/watch?V=AQ О…
привести неуместный пример
Мы хотим узнать взаимосвязь между тем, чтобы быть программистом, и тем, чтобы быть лысым, и мы можем использовать формулу Наивного Байеса, чтобы вычислить ее.
мы хотим сейчасP (лысый | быть программистом)вероятность, то естьВероятность быть программистом будет лысой
Я никогда в жизни не буду лысой(((о(゚▽゚)о))) ! ! !
Замените формулу Наивного Байеса
Известные данные таковы
Имя | Профессия | ты лысый? |
---|---|---|
Кратос | Марс | да |
Убийца 47 | убийца | да |
Сайтама | супермен | да |
Танос | Директор офиса планирования семьи | да |
Джейсон Стэтхэм | крутой парень | да |
такой-то 996 программист | программист | да |
я | программист | нет |
Основываясь на формуле Наивного Байеса, мы можем найти из приведенной выше таблицы:
Приведенный выше пример просто описывает основное использование формулы наивного Байеса.
Далее я буду использовать обзоры фильмов Douban Top250, чтобы использовать Наивный Байес для обучения и предсказания хороших и плохих отзывов.
Анализ настроений 250 лучших обзоров фильмов Douban
Прежде всего, мне нужен корпус обзоров фильмов Douban Top 250. Я использовал Scrapy, чтобы получить корпус 5w для обучения и проверки.
Сканер обзоров фильмов DoubanGitHub.com/3inch time/…
После того, как у нас есть корпус, мы можем приступить к фактической разработке.
Здесь рекомендуется использовать jupyter для разработки операций.
Следующие коды доступны на моем Github, и предложения приветствуются.
Сначала загрузите корпус
# -*- coding: utf-8 -*-
import random
import numpy as np
import csv
import jieba
file_path = './data/review.csv'
jieba.load_userdict('./data/userdict.txt')
# 读取保存为csv格式的语料
def load_corpus(corpus_path):
with open(corpus_path, 'r') as f:
reader = csv.reader(f)
rows = [row for row in reader]
review_data = np.array(rows).tolist()
random.shuffle(review_data)
review_list = []
sentiment_list = []
for words in review_data:
review_list.append(words[1])
sentiment_list.append(words[0])
return review_list, sentiment_list
Перед обучением набор данных обычно перемешивается, порядок между данными нарушается, а данные рандомизируются, что позволяет избежать переобучения. так что используйтеrandom.shuffle()
метод перемешивания данных.
jieba.load_userdict('./data/userdict.txt')
Здесь я сам сделал словарь, чтобы предотвратить неточность сегментации некоторых заикающихся слов, что может повысить точность примерно на 1%.
Напримерне очень нравитсяВ этом предложении jieba будет делиться на два слова: «не» и «очень нравится», что приводит к высокой вероятности того, что это предложение будет предсказуемо как положительный комментарий.
Итак, здесь я разделил много таких слов в пользовательском словаре, что немного повысило точность.
Затем весь корпус делится на тестовую и обучающую выборки в соотношении 1:4.
n = len(review_list) // 5
train_review_list, train_sentiment_list = review_list[n:], sentiment_list[n:]
test_review_list, test_sentiment_list = review_list[:n], sentiment_list[:n]
Причастие
Используйте сегментацию слов jieba, чтобы сегментировать корпус и удалить стоп-слова.
import re
import jieba
stopword_path = './data/stopwords.txt'
def load_stopwords(file_path):
stop_words = []
with open(file_path, encoding='UTF-8') as words:
stop_words.extend([i.strip() for i in words.readlines()])
return stop_words
def review_to_text(review):
stop_words = load_stopwords(stopword_path)
# 去除英文
review = re.sub("[^\u4e00-\u9fa5^a-z^A-Z]", '', review)
review = jieba.cut(review)
# 去掉停用词
if stop_words:
all_stop_words = set(stop_words)
words = [w for w in review if w not in all_stop_words]
return words
# 用于训练的评论
review_train = [' '.join(review_to_text(review)) for review in train_review_list]
# 对于训练评论对应的好评/差评
sentiment_train = train_sentiment_list
# 用于测试的评论
review_test = [' '.join(review_to_text(review)) for review in test_review_list]
# 对于测试评论对应的好评/差评
sentiment_test = test_sentiment_list
TF*IDF и векторизация частоты слов
TF-IDF (это метод взвешивания, обычно используемый при обработке информации и интеллектуальном анализе данных. Вычисляет важность слова во всем корпусе в соответствии с тем, сколько раз это слово появляется в тексте, и частотой появления документа во всем корпусе.
Его преимущество заключается в том, что он отфильтровывает некоторые общие, но нерелевантные слова, сохраняя при этом важные слова, влияющие на весь текст.
использоватьCountvectorizer()
Преобразуйте документ в вектор и подсчитайте, как часто слова появляются в тексте.
CountVectorizer
Класс преобразует слова в тексте в матрицу частоты слов, например, матрица содержит элемент a[i][j], который представляет частоту слова j в тексте класса i. Он подсчитывает количество вхождений каждого слова с помощью функции fit_transform.
TfidfTransformer используется для подсчета значения TF-IDF каждого слова в векторизаторе.
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.pipeline import Pipeline
from sklearn.naive_bayes import MultinomialNB
count_vec = CountVectorizer(max_df=0.8, min_df=3)
tfidf_vec = TfidfVectorizer()
# 定义Pipeline对全部步骤的流式化封装和管理,可以很方便地使参数集在新数据集(比如测试集)上被重复使用。
def MNB_Classifier():
return Pipeline([
('count_vec', CountVectorizer()),
('mnb', MultinomialNB())
])
max_df
Функция этого параметра является пороговой.При построении набора ключевых слов корпуса, если частотность слова больше, чемmax_df
, это слово не будет рассматриваться как ключевое слово.
Если этот параметр имеет значение float, он указывает процентное соотношение количества вхождений слова к количеству документов корпуса, если он имеет значение int, он указывает количество вхождений слова.
min_df
похожий наmax_df
, разница в том, что если частота слова слова меньше, чемmin_df
, слово не будет рассматриваться как ключевое слово
Таким образом, мы успешно построили конвейер для обучения и тестирования.
затем используйтеPipeline.fit() тренироваться на тренировочном наборе
использовать напрямуюPipeline.score()Предсказать и оценить на тестовом наборе
mnbc_clf = MNB_Classifier()
# 进行训练
mnbc_clf.fit(review_train, sentiment_train)
# 测试集准确率
print('测试集准确率: {}'.format(mnbc_clf.score(review_test, sentiment_test)))
Таким образом, мы завершили весь процесс от обучения до тестирования.
В основном, правильная скорость тестового набора составляет около 79%-80%.
Потому что в большом проценте обзоров фильмов есть негативные сентиментальные слова, например, в документальном фильме « Бухта дельфинов».
Я думаю, что большинство людей, которые смотрят этот фильм, не будут знать, что морская свинья байцзи в Китае вымерла уже 8 лет, и они не будут знать, что в реке Янцзы осталось всего около 1000 бесперых морских свиней. Вместо того, чтобы вздыхать и проклинать, как японцы охотятся и убивают дельфинов, лучше заняться чем-то практическим и защитить беспёрых морских свиней в реке Янцзы, которые вымрут через несколько лет. То, что делают китайцы, ничем не лучше маленькой Японии.
Поэтому, если такие подобные похвалы убрать, точность можно повысить.
Сохраните обученную модель
# 先转换成词频矩阵,再计算TFIDF值
tfidf = tfidftransformer.fit_transform(vectorizer.fit_transform(review_train))
# 朴素贝叶斯中的多项式分类器
clf = MultinomialNB().fit(tfidf, sentiment_train)
with open(model_export_path, 'wb') as file:
d = {
"clf": clf,
"vectorizer": vectorizer,
"tfidftransformer": tfidftransformer,
}
pickle.dump(d, file)
Прогнозирование тональности обзоров фильмов с использованием обученной модели
Здесь я напрямую вставляю весь исходный код, код очень простой, всю логику обработки я инкапсулирую в класс, поэтому очень удобно пользоваться.
Если вам это нужно, вы можете клонировать его прямо на моем Github.
# -*- coding: utf-8 -*-
import re
import pickle
import numpy as np
import jieba
class SentimentAnalyzer(object):
def __init__(self, model_path, userdict_path, stopword_path):
self.clf = None
self.vectorizer = None
self.tfidftransformer = None
self.model_path = model_path
self.stopword_path = stopword_path
self.userdict_path = userdict_path
self.stop_words = []
self.tokenizer = jieba.Tokenizer()
self.initialize()
# 加载模型
def initialize(self):
with open(self.stopword_path, encoding='UTF-8') as words:
self.stop_words = [i.strip() for i in words.readlines()]
with open(self.model_path, 'rb') as file:
model = pickle.load(file)
self.clf = model['clf']
self.vectorizer = model['vectorizer']
self.tfidftransformer = model['tfidftransformer']
if self.userdict_path:
self.tokenizer.load_userdict(self.userdict_path)
# 过滤文字中的英文与无关文字
def replace_text(self, text):
text = re.sub('((https?|ftp|file)://)?[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|].(com|cn)', '', text)
text = text.replace('\u3000', '').replace('\xa0', '').replace('”', '').replace('"', '')
text = text.replace(' ', '').replace('↵', '').replace('\n', '').replace('\r', '').replace('\t', '').replace(')', '')
text_corpus = re.split('[!。?;……;]', text)
return text_corpus
# 情感分析计算
def predict_score(self, text_corpus):
# 分词
docs = [self.__cut_word(sentence) for sentence in text_corpus]
new_tfidf = self.tfidftransformer.transform(self.vectorizer.transform(docs))
predicted = self.clf.predict_proba(new_tfidf)
# 四舍五入,保留三位
result = np.around(predicted, decimals=3)
return result
# jieba分词
def __cut_word(self, sentence):
words = [i for i in self.tokenizer.cut(sentence) if i not in self.stop_words]
result = ' '.join(words)
return result
def analyze(self, text):
text_corpus = self.replace_text(text)
result = self.predict_score(text_corpus)
neg = result[0][0]
pos = result[0][1]
print('差评: {} 好评: {}'.format(neg, pos))
Чтобы использовать, просто создайте экземпляр этого анализатора и используйтеanalyze()
метод подойдет.
# -*- coding: utf-8 -*-
from native_bayes_sentiment_analyzer import SentimentAnalyzer
model_path = './data/bayes.pkl'
userdict_path = './data/userdict.txt'
stopword_path = './data/stopwords.txt'
corpus_path = './data/review.csv'
analyzer = SentimentAnalyzer(model_path=model_path, stopword_path=stopword_path, userdict_path=userdict_path)
text = '倍感失望的一部诺兰的电影,感觉更像是盗梦帮的一场大杂烩。虽然看之前就知道肯定是一部无法超越前传2的蝙蝠狭,但真心没想到能差到这个地步。节奏的把控的失误和角色的定位模糊绝对是整部影片的硬伤。'
analyzer.analyze(text=text)
Все приведенные выше коды были отправлены на мой Github, и предложения приветствуются.