В недавнем проекте у меня была возможность изучить анализ описательного текста с помощью НЛП. Хотя этот вариант использования был другим и был связан с Healthtech, я был очень взволнован возможностями НЛП. Я искал совершенно другой вариант использования, чем Healthtech, чтобы больше изучить НЛП и лучше понять его возможности. И тут меня осенило. Как известно большинству читателей, в настоящее время в Индии проходят всеобщие выборы. Через несколько недель мы выберем новое правительство или снова проголосуем за нынешнее к власти. Массовое проявление демократии, которому мало аналогов в мире (а может, и нет). Я решил проанализировать манифесты двух основных политических партий с помощью НЛП.

Прежде чем мы начнем, кратко о НЛП:

  • Это подполе более крупного зонтика ИИ. Имеет дело с взаимодействием между программным обеспечением и человеческим языком и интерпретациями.
  • Это особенно полезно при работе с неструктурированными данными в виде текста, который лежит на веб-страницах, документах и ​​т. д.
  • Области применения включают в себя — машинный перевод, автоматическое создание резюме, анализ тональности, классификацию текста и многое другое.

Для получения дополнительной информации о НЛП перейдите по этой ссылке.

Цель этой статьи — объяснить, как НЛП можно использовать для лучшего понимания блока текста и получения на его основе аналитических данных. Текстовая аналитика очень полезна, если ее можно превратить в объективные данные и осмысленные выводы. В большинстве случаев полезные данные по любой интересующей теме обычно доступны в текстовом виде.

Возвращаясь к нашему конкретному варианту использования. Оценим манифесты обеих основных национальных политических партий Индии — БДП и Конгресса. Они оба когда-то выпустили свои манифесты, и я подумал, что было бы неплохо посмотреть, поможет ли НЛП извлечь из них интересные выводы. Для начала я скачал оба манифеста в формате PDF (доступны на сайтах обеих сторон). Из-за нехватки времени с моей стороны я решил сначала проанализировать только раздел предисловия в манифестах. Предисловие БДП приписывается премьер-министру Нарендре Моди, а предисловие к Конгрессу приписывается ее национальному президенту Рахулу Ганди.

У меня есть полный анализ в блокноте Jupyter, который доступен на моем Github здесь. Github отобразит большую часть (но не всю) записной книжки. Я предлагаю вам использовать nbviewer для просмотра и запуска блокнота (вставьте URL-адрес Github выше в панель nbviewer. Блокнот будет работать в Binder).

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

Я использовал spaCy, TextBlob и Vader в качестве основных библиотек НЛП. Кроме того, я использую некоторые утилиты, такие как WordCloud, pyplot и так далее.

Первое, что я делаю, это устанавливаю необходимые пакеты и выполняю несколько простых тестовых прогонов. Перейдите к ячейке 12 под названием «BJP 2019» (как «В [12]:» в блокноте). Здесь я сохраняю предисловие BJP в переменной:

text_bjp = '''
The BJP comes to you to seek your valued blessings yet again,...
...
prosperity, security and opportunity.
'''

Сразу после этого я хочу увидеть общее настроение, выраженное в предисловии. Я использую TextBlob в этом случае.

blob_bjp = TextBlob(text_bjp)
print("Sentiment: ", blob_bjp.sentiment, "\n")

Результат:

Sentiment:  Sentiment(polarity=0.10652188552188553, subjectivity=0.47387542087542084)

Вот как это читать:

  • полярность близка к нейтральной (0,1 близка к нулю) — это ни положительное, ни отрицательное настроение
  • субъективность равна 0,47, что означает, что она не слишком субъективна и не слишком объективна. Снова нейтральный балл

Теперь давайте проведем небольшой лингвистический анализ и найдем все существительные в предисловии BJP.

bjp_nouns = blob_bjp.noun_phrases
print("Found ", len(bjp_nouns), " nouns. Here they all are:\n")
print(bjp_nouns)

Выход:

Found  102  nouns. Here they all are:

['bjp', 'india', 'true destiny', 'may', 'great nation', 'historic mandate', 'india', 'fragile \U001000aave', 'serious doubts', 'india', "'s ability", 'prosperous nation', 'powered', 'unimaginable speed', 'indian family', 'bank account', 'jan dhan yojana', 'health insurance thanks', 'ayushman bharat', 'crore people', 'avail pension coverage', '% sanitation coverage', 'entrepreneurs thanks', 'mudra yojana', 'middle class', 'taxable income upto', 'rs', 'income tax', 'infrastructure gaps', 'railway lines', 'india', 'efficient ports', 'darkness till', 'lit thanks', 'rural electrification efforts', 'crore homes', 'saubhagya yojana', 'crore homes', 'barbaric forces', 'destructive ideology', 'own coin', 'compound interest', 'india', 'unprecedented development', 'national mainstream', 'central government', 'black money', 'public interest', 'jan dhan- aadhaar', 'mobile', 'crore fake beneficiaries', 'rs', 'lakh crore', 'systems', 'mass movement', 'numerous', 'friendly decisions', 'strategic interests', 'india', 'international level', 'india', "'s immense potential", 'record rise', 'foreign investment', 'india', "'s stand", 'global narrative', 'sankalp patra', 'indomitable efforts', 'collective vision', 'passionate about-', 'farmer income', 'patriotic citizens', 'india', 'sankalp patra', 'valuable inputs', 'sankalp patra', 'truest sense', 'your', 'decisive government', 'dynastic rule', 'short span', 'independence', 'generations', 'great women', 'india', 'india', 'bjp', 'india', 'golden reality', 'different political parties', 'india', 'bjp', 'mantra', 'saath', 'sabka vikas', 'india', 'bjp', 'grassroots level', 'india', 'together', 'india']

Давайте проследим тональность каждого существительного:

noun_polarities = []

for n in bjp_nouns:
  noun_polarities.append(TextBlob(n).sentiment.polarity)
  print(TextBlob(n).sentiment.polarity, "\n")

Вывод доступен в записной книжке. Мы также можем посмотреть на визуализацию того же самого:

from matplotlib import pyplot as plt
plt.plot(noun_polarities)

Из вышеизложенного мы можем видеть, что полярность отдельных существительных смещена в сторону +ve. Наконец, давайте получим количество слов для общих слов в этом домене (количество слов = сколько раз конкретное слово появляется в предисловии):

print(blob_bjp.word_counts['bjp'])
print(blob_bjp.word_counts['india'])
print(blob_bjp.word_counts['women'])
print(blob_bjp.word_counts['congress'])
print(blob_bjp.word_counts['modi'])
print(blob_bjp.word_counts['gandhi'])

Выход:

4
16
1
0
0
0

Из вышеизложенного мы видим, что слово «Индия» имеет высокую частоту, а слово «Женщины» — низкую.

Теперь сделаем все то же самое для предисловия Конгресса. Предисловие в переменной:

congress_text = '''
Elections 2019 present a stark choice...
.......
Congress promises. Congress delivers.
'''

Анализ тональности всего предисловия:

blob_congress = TextBlob(congress_text)
print("Sentiment: ", blob_congress.sentiment, "\n")

Выход:

Sentiment:  Sentiment(polarity=0.1074099659206042, subjectivity=0.4664387031408308)

Это очень похоже на оценки настроений BJP. В целом нейтральный тон. Находим существительные:

congress_nouns = blob_congress.noun_phrases
print("Found ", len(congress_nouns), " nouns. Here they all are:\n")
print(congress_nouns)

Вывод:

Found  56  nouns. Here they all are:

['elections', 'stark choice', 'india', 'will india', 'democratic country', 'indian people', 'india', 'pernicious ideology', 'people ’ s rights', 'healthy differences', 'multi-cultural country', 'will india', 'india', 'gross inequalities', 'india', 'traders', 'micro', 'medium enterprises', 'deprived', 'traditional rights', 'institutions', 'harshest blow', 'prime', 'empty slogans', 'false statistics', 'overall climate', 'deep crisis', 'congress', 'congress', 'national alternative', 'india', 'prosperous society', 'manifesto process reflects', 'jan awaaz', '‘ mann ki baat ’', 'collective voice', 'possible tools—website', 'whatsapp', 'grassroots activists', 'october', 'february', 'congress', 'manifesto', 'women ’ s groups', 'territories', 'nri', 'people ’ s voices', 'congress', 'manifesto reflects', 'action plan', 'india', 'india', 'independent social audit group', 'own assessment', 'congress', 'congress']

Визуализация настроения для каждого существительного:

con_noun_polarities = []

for n in congress_nouns:
  con_noun_polarities.append(TextBlob(n).sentiment.polarity)
plt.plot(con_noun_polarities)

Мы можем видеть, что в предисловии Конгресса существительные редки, и, как правило, отдельные полярности существительных нейтральны по тону (по крайней мере, как видно на графике). Редкость связана с тем, что предисловие Конгресса составляет ~ 500 слов по сравнению с ~ 1000 слов БДП.

Ну наконец то. давайте найдем количество слов для некоторых распространенных терминов в этой области:

print(blob_congress.word_counts['congress'])
print(blob_congress.word_counts['india'])
print(blob_congress.word_counts['women'])
print(blob_congress.word_counts['modi'])
print(blob_congress.word_counts['gandhi'])
print(blob_congress.word_counts['bjp'])

Вывод:

6
9
2
0
0
0

Из вышеизложенного мы видим, что слова «Конгресс» и «Индия» имеют высокую частоту, а слово «Женщины» — низкую, но на единицу больше, чем в манифесте БДП.

И первоначальный общий анализ предисловия, и анализ настроений (в целом) нейтральны по тону (ни -ve, ни +ve) и сбалансированы между объективностью и субъективностью. Не слишком удивительно, учитывая, что это важный раздел в манифесте. Вопрос в следующем: можем ли мы извлечь из предисловия больше данных, которые дадут нам дополнительную (скрытую) информацию?

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

Давайте построим облако слов для обоих предисловий;

from wordcloud import WordCloud, STOPWORDS

stopwords = set(STOPWORDS)
#bjp
comment_words_bjp = text_bjp
wordcloudbjp = WordCloud(width = 800, height = 800, 
                background_color ='white', 
                stopwords = stopwords, 
                min_font_size = 10).generate(comment_words_bjp)
plt.figure(figsize = (8, 8), facecolor = None) 
plt.imshow(wordcloudbjp) 
plt.axis("off") 
plt.tight_layout(pad = 0) 
plt.show()
#congress
comment_words_congress = congress_text
wordcloudcongress = WordCloud(width = 800, height = 800, 
                background_color ='white', 
                stopwords = stopwords, 
                min_font_size = 10).generate(comment_words_congress)
plt.figure(figsize = (8, 8), facecolor = None) 
plt.imshow(wordcloudcongress) 
plt.axis("off") 
plt.tight_layout(pad = 0) 
plt.show()

Вывод:

Теперь занавес немного приоткрывается и показывает нам проблеск потенциальных идей. Предисловие BJP в значительной степени сосредоточено на «сейчас», Индии, нации, индийцах и, что интересно, крорах. В предисловии к Конгрессу основное внимание уделяется манифесту, людям, воле, Индии и интересным, потерянным. Если вы следили за выборами, то делайте из этого выводы сами!

В нашем арсенале новые инструменты, Vader & spaCy. Вместе они полезны для анализа настроений. Всегда полезно использовать несколько известных библиотек, чтобы делать выводы в таких случаях. Мы будем использовать их, чтобы посмотреть на настроение отдельных предложений в предисловии.

import spacy
from vaderSentiment import vaderSentiment
english = spacy.load("en_core_web_sm")
analyzer = vaderSentiment.SentimentIntensityAnalyzer()

Для БДП:

result_bjp = english(text_bjp)
sentences_bjp = [str(s) for s in result_bjp.sents]
sentiment_bjp = [analyzer.polarity_scores(str(s)) for s in sentences_bjp]
print(sentiment_bjp)

Вывод:

[{'neg': 0.0, 'neu': 0.701, 'pos': 0.299, 'compound': 0.8779}, {'neg': 0.0, 'neu': 0.762, 'pos': 0.238, 'compound': 0.8176}, {'neg': 0.15, 'neu': 0.81, 'pos': 0.04, 'compound': -0.5423}, {'neg': 0.137, 'neu': 0.667, 'pos': 0.196, 'compound': 0.3612}, {'neg': 0.0, 'neu': 0.4, 'pos': 0.6, 'compound': 0.9477}, {'neg': 0.213, 'neu': 0.464, 'pos': 0.322, 'compound': 0.6124}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.932, 'pos': 0.068, 'compound': 0.4404}, {'neg': 0.0, 'neu': 0.902, 'pos': 0.098, 'compound': 0.3612}, {'neg': 0.0, 'neu': 0.838, 'pos': 0.162, 'compound': 0.4404}, {'neg': 0.175, 'neu': 0.825, 'pos': 0.0, 'compound': -0.3818}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.618, 'pos': 0.382, 'compound': 0.4754}, {'neg': 0.098, 'neu': 0.637, 'pos': 0.265, 'compound': 0.5267}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.882, 'pos': 0.118, 'compound': 0.25}, {'neg': 0.489, 'neu': 0.511, 'pos': 0.0, 'compound': -0.8225}, {'neg': 0.291, 'neu': 0.575, 'pos': 0.134, 'compound': -0.6249}, {'neg': 0.0, 'neu': 0.786, 'pos': 0.214, 'compound': 0.4588}, {'neg': 0.176, 'neu': 0.824, 'pos': 0.0, 'compound': -0.4588}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.854, 'pos': 0.146, 'compound': 0.34}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.833, 'pos': 0.167, 'compound': 0.4588}, {'neg': 0.119, 'neu': 0.731, 'pos': 0.15, 'compound': -0.0516}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.606, 'pos': 0.394, 'compound': 0.4404}, {'neg': 0.145, 'neu': 0.855, 'pos': 0.0, 'compound': -0.296}, {'neg': 0.0, 'neu': 0.769, 'pos': 0.231, 'compound': 0.4019}, {'neg': 0.0, 'neu': 0.7, 'pos': 0.3, 'compound': 0.743}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.847, 'pos': 0.153, 'compound': 0.4019}, {'neg': 0.199, 'neu': 0.693, 'pos': 0.108, 'compound': -0.4767}, {'neg': 0.0, 'neu': 0.796, 'pos': 0.204, 'compound': 0.6908}, {'neg': 0.0, 'neu': 0.92, 'pos': 0.08, 'compound': 0.0772}, {'neg': 0.0, 'neu': 0.785, 'pos': 0.215, 'compound': 0.6361}, {'neg': 0.0, 'neu': 0.545, 'pos': 0.455, 'compound': 0.6124}, {'neg': 0.0, 'neu': 0.618, 'pos': 0.382, 'compound': 0.836}, {'neg': 0.0, 'neu': 0.805, 'pos': 0.195, 'compound': 0.4404}, {'neg': 0.0, 'neu': 0.848, 'pos': 0.152, 'compound': 0.6369}, {'neg': 0.0, 'neu': 0.862, 'pos': 0.138, 'compound': 0.4939}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.672, 'pos': 0.328, 'compound': 0.8519}, {'neg': 0.0, 'neu': 0.676, 'pos': 0.324, 'compound': 0.5859}, {'neg': 0.0, 'neu': 0.682, 'pos': 0.318, 'compound': 0.6369}, {'neg': 0.0, 'neu': 0.915, 'pos': 0.085, 'compound': 0.0772}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.8, 'pos': 0.2, 'compound': 0.5423}, {'neg': 0.071, 'neu': 0.714, 'pos': 0.214, 'compound': 0.6597}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.649, 'pos': 0.351, 'compound': 0.4019}, {'neg': 0.0, 'neu': 0.769, 'pos': 0.231, 'compound': 0.4019}, {'neg': 0.0, 'neu': 0.816, 'pos': 0.184, 'compound': 0.4019}, {'neg': 0.256, 'neu': 0.744, 'pos': 0.0, 'compound': -0.4767}, {'neg': 0.0, 'neu': 0.71, 'pos': 0.29, 'compound': 0.5423}, {'neg': 0.0, 'neu': 0.705, 'pos': 0.295, 'compound': 0.5574}, {'neg': 0.0, 'neu': 0.523, 'pos': 0.477, 'compound': 0.9136}]

Выше каждое предложение в предисловии было проанализировано, и были извлечены следующие статистические данные (это из Вейдера):

  • Оценки pos, neu и neg — это отношения пропорций текста, которые попадают в каждую категорию (таким образом, все они должны в сумме равняться 1… или близко к этому при операции с плавающей запятой). Это наиболее полезные метрики, если вам нужны многомерные измерения тональности для данного предложения.
  • Составная оценка вычисляется путем суммирования оценок валентности каждого слова в лексиконе, скорректированных в соответствии с правилами, а затем нормализована так, чтобы она находилась в диапазоне от -1 (самое крайнее отрицательное) до +1 (самое крайнее положительное). Это наиболее полезная метрика, если вам нужна единая одномерная мера тональности для данного предложения.

Я оставляю читателю в качестве упражнения извлечение сложных оценок и построение графика, чтобы увидеть перекосы +ve и -ve, если таковые имеются.

Для Конгресса:

result_congress = english(congress_text)
sentences_congress = [str(s) for s in result_congress.sents]
sentiment_congress = [analyzer.polarity_scores(str(s)) for s in sentences_congress]
print(sentiment_congress)

Вывод:

[{'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.708, 'pos': 0.292, 'compound': 0.5106}, {'neg': 0.125, 'neu': 0.463, 'pos': 0.411, 'compound': 0.93}, {'neg': 0.0, 'neu': 0.906, 'pos': 0.094, 'compound': 0.4019}, {'neg': 0.148, 'neu': 0.718, 'pos': 0.134, 'compound': -0.1531}, {'neg': 0.281, 'neu': 0.719, 'pos': 0.0, 'compound': -0.5994}, {'neg': 0.434, 'neu': 0.566, 'pos': 0.0, 'compound': -0.3182}, {'neg': 0.319, 'neu': 0.278, 'pos': 0.403, 'compound': 0.1531}, {'neg': 0.434, 'neu': 0.566, 'pos': 0.0, 'compound': -0.3182}, {'neg': 0.183, 'neu': 0.556, 'pos': 0.262, 'compound': 0.25}, {'neg': 0.264, 'neu': 0.46, 'pos': 0.276, 'compound': 0.0258}, {'neg': 0.519, 'neu': 0.481, 'pos': 0.0, 'compound': -0.6597}, {'neg': 0.434, 'neu': 0.566, 'pos': 0.0, 'compound': -0.3182}, {'neg': 0.23, 'neu': 0.667, 'pos': 0.104, 'compound': -0.5267}, {'neg': 0.451, 'neu': 0.472, 'pos': 0.077, 'compound': -0.9136}, {'neg': 0.175, 'neu': 0.598, 'pos': 0.226, 'compound': 0.0516}, {'neg': 0.0, 'neu': 0.688, 'pos': 0.312, 'compound': 0.8957}, {'neg': 0.0, 'neu': 0.439, 'pos': 0.561, 'compound': 0.8885}, {'neg': 0.0, 'neu': 0.753, 'pos': 0.247, 'compound': 0.5574}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.828, 'pos': 0.172, 'compound': 0.659}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.484, 'pos': 0.516, 'compound': 0.4939}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.722, 'pos': 0.278, 'compound': 0.4019}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}, {'neg': 0.0, 'neu': 0.822, 'pos': 0.178, 'compound': 0.6597}, {'neg': 0.0, 'neu': 0.536, 'pos': 0.464, 'compound': 0.3818}, {'neg': 0.0, 'neu': 0.278, 'pos': 0.722, 'compound': 0.3818}, {'neg': 0.0, 'neu': 1.0, 'pos': 0.0, 'compound': 0.0}]

Полный анализ предисловия в целом:

Я также решил взять весь текст предисловия для обеих сторон и пропустить их через анализатор настроений Вейдера.

Конгресс:

sentiment_congress_singledoc = [analyzer.polarity_scores(str(congress_text))]
print(sentiment_congress_singledoc)

Вывод:

[{'neg': 0.072, 'neu': 0.788, 'pos': 0.14, 'compound': 0.9873}]

БДП:

sentiment_bjp_singledoc = [analyzer.polarity_scores(str(text_bjp))]
print(sentiment_bjp_singledoc)

Вывод:

[{'neg': 0.059, 'neu': 0.731, 'pos': 0.21, 'compound': 0.9995}]

Из вышеизложенного можно сделать еще несколько выводов:

  • Соотношение пропорций текста, попадающего в категорию -ve, немного выше в предисловии Конгресса. Это означает, что он использует отрицание / отрицательные термины немного больше, чем предисловие BJP.
  • Соотношение текста нейтральной категории также выше в предисловии к Конгрессу.
  • Соотношение текста категории +ve выше в предисловии BJP
  • Общий балл тональности (составной) примерно одинаков для обоих

Лингвистический анализ на основе spaCy:

Мы также можем провести дальнейший анализ лингвистических аспектов. Например, как структурированы предложения, какие сущности доступны и так далее. spacy — отличный инструмент для того же:

БДП:

from spacy import displacy
sentence_spans = list(result_bjp.sents)
displacy.render(sentence_spans, style="dep", jupyter=True)

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

Код ниже извлекает объекты:

displacy.render(result_bjp, style="ent", jupyter=True)

Выходной фрагмент (частичный):

Конгресс:

sentence_spans = list(result_congress.sents)
displacy.render(sentence_spans, style="dep", jupyter=True)

displacy.render(result_congress, style="ent", jupyter=True)

Лингвистический анализ очень полезен для извлечения именованных сущностей и их отношений. Если вы ищете термины, представляющие интерес, и их отношение/объем в большом текстовом корпусе, вам подойдет лингвистический анализ.

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

Пришло время пойти глубже. Подготовьте скальпели.

Теперь мы ищем более подробные данные. Для начала давайте извлечем все глаголы из предисловий и посмотрим, что мы найдем:

БДП:

bjpverbs = set()
for possible_subject in result_bjp:
    if possible_subject.dep == nsubj and possible_subject.head.pos == VERB:
        bjpverbs.add(possible_subject.head)
print(bjpverbs)
print(type(bjpverbs))

Вывод:

{work, continues, were, is, am, conve􀄒ed, weeded, enriched, are, received, laid, begun, are, commenced, want, doubled, is, broken, need, get, seemed, is, witnessing, were, mark, daring, achieved, made, been, work, stands, was, see, is, is, is, is, complete, are, is, want, setting, got, got, address, filled, is, is, ignited, is, become, are, waged, is, thank, lay, are, resonated, led, become, recognizes, happen, enabled, imagine, destroys, breathe, was, comes, works, has, am, is}
<class 'set'>

Давайте создадим облако слов из всех глаголов. Визуализация снова может помочь.

verbasstring = str(bjpverbs)
wordcloudbjpverbs = WordCloud(width = 800, height = 800,
                background_color ='white',
                stopwords = stopwords,
                min_font_size = 10).generate(verbasstring)
plt.figure(figsize = (8, 8), facecolor = None)
plt.imshow(wordcloudbjpverbs)
plt.axis("off")
plt.tight_layout(pad = 0)
plt.show()

Вывод:

Проделаем то же самое и с существительными. Мы уже извлекали существительные ранее. Построим и для них облако слов:

print(type(bjp_nouns))
wordcloudbjpnouns = WordCloud(width = 800, height = 800,
                background_color ='white',
                stopwords = stopwords,
                min_font_size = 10).generate(str(bjp_nouns))
plt.figure(figsize = (8, 8), facecolor = None)
plt.imshow(wordcloudbjpnouns)
plt.axis("off")
plt.tight_layout(pad = 0)
plt.show()

Вывод:

Конгресс:

congressverbs = set()
for possible_subject in result_congress:
    if possible_subject.dep == nsubj and possible_subject.head.pos == VERB:
        congressverbs.add(possible_subject.head)
print(congressverbs)
print(type(congressverbs))

Вывод:

{fulfilled, reflects, promises, set, offers, used, promise, lost, is, given, is, be, delivers, present, inspired, lost, be, is, met, needs, get, listening, is, lost, promises, is, are, lost, lost, organised, engaged, held, become, make, lost, present, been, be, lost, reflects, lost, trample, is}
<class 'set'>

Построение облака слов глагола:

verbasstring = str(congressverbs)
print(type(verbasstring))
print(verbasstring)
wordcloudcongressverbs = WordCloud(width = 800, height = 800,
                background_color ='white',
                stopwords = stopwords,
                min_font_size = 10).generate(verbasstring)
plt.figure(figsize = (8, 8), facecolor = None)
plt.imshow(wordcloudcongressverbs)
plt.axis("off")
plt.tight_layout(pad = 0)
plt.show()

Вывод:

Теперь о существительных:

print(type(congress_nouns))
wordcloudcongressnouns = WordCloud(width = 800, height = 800,
                background_color ='white',
                stopwords = stopwords,
                min_font_size = 10).generate(str(congress_nouns))
plt.figure(figsize = (8, 8), facecolor = None)
plt.imshow(wordcloudcongressnouns)
plt.axis("off")
plt.tight_layout(pad = 0)
plt.show()

Вывод:

Облака слов обеих сторон полезны. Они явно указывают на некий перекос полярности и, следовательно, на отношение к каждому манифесту. Чтобы получить объективные данные, давайте посмотрим, сможем ли мы получить оценки тональности для глаголов и существительных для каждого из них. Обратите внимание, что нам нужно воспринимать их с долей скептицизма, поскольку используется алгоритм Вейдера по умолчанию. Полный анализ позволит изучить другие возможные алгоритмы и компромиссы, а также применимость к проблемной области.

Сначала общее отношение к существительным.

Конгресс:

sentiment_congress_singlenoun = [analyzer.polarity_scores(str(congress_nouns))]
print(sentiment_congress_singlenoun)

Вывод:

[{'neg': 0.086, 'neu': 0.858, 'pos': 0.057, 'compound': -0.4588}]

БДП:

sentiment_bjp_singlenoun = [analyzer.polarity_scores(str(bjp_nouns))]
print(sentiment_bjp_singlenoun)

Вывод:

[{'neg': 0.05, 'neu': 0.8, 'pos': 0.15, 'compound': 0.9682}]

Общее настроение глагола следующее.

БДП:

verbasstringbjp = str(bjpverbs)
sentiment_bjp_singleverb = [analyzer.polarity_scores(str(verbasstringbjp))]
print(sentiment_bjp_singleverb)

Вывод:

[{'neg': 0.083, 'neu': 0.822, 'pos': 0.095, 'compound': -0.2732}]

Конгресс:

verbasstringcongress = str(congressverbs)
sentiment_congress_singleverb = [analyzer.polarity_scores(str(verbasstringcongress))]
print(sentiment_congress_singleverb)

Вывод:

[{'neg': 0.298, 'neu': 0.485, 'pos': 0.217, 'compound': -0.4588}]

Мы обсудим только сложные баллы обеих сторон.

  • Настроения существительных резко различаются. В предисловии Конгресса используются существительные с гораздо более негативным контекстом, чем в предисловии BJP.
  • Глагольные настроения для обоих схожи в том смысле, что оба используют глаголы в более отрицательном контексте, чем в положительном. Тем не менее, предисловие Конгресса действительно более склонно к негативному

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

Спасибо, что прочитали эту статью! Я приветствую любые комментарии или вопросы, которые могут у вас возникнуть. Я независимый консультант по технологиям в области цифровой трансформации и смежных областях. Я помогаю организациям перейти к использованию таких технологий, как облачные вычисления, Интернет вещей, мобильные приложения и другие, для их бизнеса. Совсем недавно я помог запустить, спроектировать и создать прототип платформы биологической обратной связи, а также помогаю организациям в сфере теплоснабжения и Интернета вещей. Если вы или ваша организация ищете помощь в цифровой трансформации, напишите мне сообщение!