Когда мы читаем текст или предложение, мы обычно легко можем определить, является ли оно положительным, отрицательным или нейтральным. Но если нам нужно пройти через большое количество писем или предложений, работа может быть очень требовательной. Вместо этого мы могли бы выполнить анализ тональности, который сочетает в себе методы обработки естественного языка и машинного обучения для анализа тональности текстов.

Анализ настроений в контексте машинного обучения можно разделить на два вида: контролируемое и неконтролируемое обучение. Обучение с учителем – это тип подхода к машинному обучению, который определяется использованием помеченных наборов данных для обучения моделей, а обучение без учителя изучает шаблоны из немаркированных данных.

Контролируемое обучение анализу тональности позволяет нам обучать модель машинного обучения с помощью обучающих данных, и на основе обученной модели мы можем выполнять анализ тональности данного текста или корпуса. С другой стороны, неконтролируемый анализ настроений использует своего рода «словарь анализа настроений», такой как «Лексикон», который в основном представляет собой набор информации о словах языка.

В этой статье основное внимание будет уделено выполнению неконтролируемого анализа тональности в Python с помощью SentiWordNet.

Неконтролируемый анализ настроений не требует обучения модели машинного обучения. Скорее, это тип анализа настроений, основанный на лексике. При анализе тональности на основе словарного запаса или неконтролируемом анализе тональности слова помечаются как положительные, отрицательные или нейтральные с помощью словаря валентности. Словарь валентности количественно определяет и присваивает положительное или отрицательное значение каждому рассматриваемому слову. контекст, часть речи и т. д. Эта оценка, присваиваемая слову, называется оценкой полярности.

Существует несколько библиотек, которые предоставляют связанные пакеты для неконтролируемого анализа тональности, такие как SentiWordNet, VADER и Pattern. Давайте сосредоточимся на SentiWordNet и VADER в этой конкретной статье.

Анализ настроений с помощью SentiWordNet

SentiWordNet использует Synset, основанный на Wordnet, лексической базе данных семантических отношений между словами на более чем 200 языках. Чтобы использовать Wordnet, нам сначала нужно загрузить все подпакеты NLTK, а также наборы данных. Вы можете сделать это, запустив код ниже. nltk.download('all') может занять некоторое время, поскольку загружает большое количество данных.

import nltk
nltk.download('all')

Синсет

Synset — это особый вид простого интерфейса, присутствующего в NLTK, для поиска слов в Wordnet. Давайте попробуем и посмотрим, как Synset работает в Python. Это легче понять с помощью простых кодов.

from nltk.corpus import wordnet as wn
term = 'book'
synsets = wn.synsets(term)
print(synsets)

Со словом «книга» запуск synsets() возвращает один список, содержащий различные объекты. Каждый объект Synset представляет собой часть речи (POS). Например, в первом объекте Synset('book.n.01') book — это само слово, n обозначает существительное как часть речи, а 01 — индекс.

Мы можем извлечь некоторую информацию из объектов Synset.

term = 'book'
book_1 = wn.synsets(term)[0]
book_2 = wn.synsets(term)[1]

print('##### Definition 1 #####\n', book_1.definition())
print('=====Example=====\n', book_1.examples())
print('=====Lemma=====\n', book_1.lemma_names(), '\n\n')


print('##### Definition 2 #####\n', book_2.definition())
print('=====Example=====\n', book_2.examples())
print('=====Lemma=====\n', book_2.lemma_names())

Из приведенного выше результата .definition() возвращает определение, .examples() возвращает пример предложения, содержащего слово, а .lemma_names() возвращает леммы, каноническую или морфологическую форму слова, слова.

Подобие синсета

Synset также предлагает методы, которые позволяют нам видеть, насколько похожи слова. Мы будем тестировать три разных метода вычисления степени сходства между двумя словами.

wup_similarity() - Сходство Ву-Палмера, метод оценки, который вычисляет родство, учитывая глубину двух синсетов в таксономиях WordNet.

path_similarity() — находит кратчайшее расстояние между двумя синсетами

lch_similarity() — расширенная версия подобия на основе пути, которая дополнительно включает глубину таксономии.

Детали этих методов измерения сходства не будут обсуждаться в этой статье, поэтому давайте попробуем их с помощью простых строк кода, сравнив слова, связанные с животными.

dog = wn.synset('dog.n.01')
puppy = wn.synset('puppy.n.01')
giraffe = wn.synset('giraffe.n.01')
lion = wn.synset('lion.n.01')
monkey = wn.synset('monkey.n.01')

words = [dog, puppy, giraffe, lion, monkey]

"""wup_similarity()"""
wup_scores = []
for word in words:
    score = [word.wup_similarity(word_) for word_ in words]
    wup_scores.append(score)
wup_df = pd.DataFrame(wup_scores, columns = [x.name().split('.')[0] for x in words],
                     index = [x.name().split('.')[0] for x in words])

"""wup_similarity()"""
wup_scores = []
for word in words:
    score = [word.wup_similarity(word_) for word_ in words]
    wup_scores.append(score)
wup_df = pd.DataFrame(wup_scores, columns = [x.name().split('.')[0] for x in words],
                     index = [x.name().split('.')[0] for x in words])

"""path_similarity()"""
path_scores = []
for word in words:
    score = [word.path_similarity(word_) for word_ in words]
    path_scores.append(score)
path_df = pd.DataFrame(path_scores, columns = [x.name().split('.')[0] for x in words],
                     index = [x.name().split('.')[0] for x in words])

"""lch_similarity()"""
lch_scores = []
for word in words:
    score = [word.lch_similarity(word_) for word_ in words]
    lch_scores.append(score)
lch_df = pd.DataFrame(lch_scores, columns = [x.name().split('.')[0] for x in words],
                     index = [x.name().split('.')[0] for x in words])

print('=====wup_similarity=====\n', wup_df)
print('\n=====path_similarity=====\n', path_df)
print('\n=====lch_similarity=====\n', lch_df)

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

SentiWordNet

SentiWordNet — это лексический ресурс для поддержки классификации настроений и анализа мнений. Он доступен на Python, и давайте проверим его здесь.

senti_synsets() из SentiWordNet работает аналогично synsets() из WordNet. Вот пример ниже. Со словом «книга» вы можете видеть, что многие синсеты возвращаются с использованием senti_synsets() из SentiWordNet.

import nltk
from nltk.corpus import sentiwordnet as swn

senti_synsets = list(swn.senti_synsets('book'))
senti_synsets

SentiWordNet также предоставляет методы, которые возвращают положительную, отрицательную и объективную оценку для слов, которые возвращаются при запуске .pos_score() , .neg_score() и .obj_score() . Вот пример ниже.

word = swn.senti_synset('book.n.01')

print('=== word: book ===')
print('Positive score: ',word.pos_score())
print('Negative score: ',word.neg_score())
print('Objective score: ',word.obj_score())

word2 = swn.senti_synset('happy.a.01')
print('\n=== word: happy ===')
print('Positive score: ',word2.pos_score())
print('Negative score: ',word2.neg_score())
print('Objective score: ',word2.obj_score())

Со словом «книга» возвращался ноль как для положительных, так и для отрицательных оценок, и 1 для объективной оценки. С другой стороны, для слова «счастливый» положительная оценка составила 0,875, отрицательная — 0, а объективная оценка — 0,125. Кроме того, вы можете видеть, что сумма положительных, отрицательных и объективных оценок равна 1.

Анализ настроений с VADER

VADER (Valence Aware Dictionary and sEntiment Reasoner) – это инструмент анализа настроений на основе лексики и правил, предназначенный специально для настроений в социальных сетях. VADER предоставляет различные инструменты через класс SentimentIntensityAnalyzer. Поскольку мы уже установили этот класс выше, запустив nltk.download('all'), давайте сразу перейдем к примерам.

Ниже приведен пример рецензии на один из фильмов на IMDb, онлайн-базе данных, связанной с фильмами. Давайте попробуем проанализировать настроение этого следующего обзора.

«После того, как все это произошло в тот момент с MJ, я начал слушать его музыку, смотреть странные документальные фильмы тут и там, смотреть The Wiz и снова смотреть Moonwalker. Может быть, я просто хочу получить некоторое представление об этом парне, который, как мне казалось, был действительно крутым в восьмидесятых, просто чтобы решить, виновен он или невиновен».

from nltk.sentiment.vader import SentimentIntensityAnalyzer
analyzer = SentimentIntensityAnalyzer()
review = "With all this stuff going down at the moment with MJ i've started listening to his music, watching the odd documentary here and there, watched The Wiz and watched Moonwalker again. Maybe i just want to get a certain insight into this guy who i thought was really cool in the eighties just to maybe make up my mind whether he is guilty or innocent."
scores = analyzer.polarity_scores(review)
print(scores)

С .polarity_scores() возвращаются отрицательные, нейтральные и положительные оценки, как видно из вывода выше. 'neg' , 'neu’ и 'pos' означают отрицательную, нейтральную и положительную оценку соответственно. 'compound' – это составной балл, нормализованный балл, учитывающий отрицательные, нейтральные и положительные баллы вместе. Составной балл принимает значение от -1 до +1, и чем он ближе к +1, тем позитивнее текст. В общем, составной балл больше 0,1 считается положительным настроением.

В этой статье мы стремились понять, как выполнять анализ настроений в Python с использованием SentiWordNet и VADER. Поскольку эти два слова предоставляют «словарь валентности», который уже определен, мы можем выполнять анализ тональности без необходимости обучать данные модели. Это может показаться удобным, поскольку нам не нужно обучать данные, но в то же время результат может быть менее точным, поскольку словарь валентности не зависит от контекста.

Надеюсь, эта статья помогла!