Обоснование

Канада вступает в сезон выборов 2019 года, и есть признаки того, что это будет спорное событие.

С одной стороны, либералы премьер-министра Трюдо протолкнули несколько реформ за последние 4 года, от легализации каннабиса до покупки трубопроводов. С другой стороны, энергия оппозиции в изгнании либералов за последний год значительно возросла. Консерваторы и НДП выбрали новых лидеров, и Партия зеленых набирает популярность.

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

  • Социальные сети: насколько активны аккаунты кандидата? Они заманчивы?
  • Дебаты: насколько хорошо кандидаты взаимодействуют с другими партийными платформами? Каковы основные дыры в политической стратегии их оппонентов?
  • Сторонний анализ: какие политики, предложенные кандидатами, объективно являются лучшими?

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

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

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

Мне недавно исполнилось 18 лет, и я, наконец, имею честь голосовать на федеральных выборах. Не видя серьезного инструмента для анализа выступлений премьер-министра Джастина Трюдо, я был вдохновлен на создание своей собственной.

Подход

Веб-скрапинг

Канцелярия премьер-министра публикует все стенограммы выступлений премьер-министра по адресу https://pm.gc.ca/en/news/speeches. Первой задачей, которую мне пришлось преодолеть, было загрузить все выступления в формат, который можно было бы использовать для дальнейшего анализа.

Введите парсинг веб-страниц. Скрипты очистки веб-страниц программно анализируют текст с определенного веб-сайта и отображают его в формате, которым можно управлять с помощью дополнительного кода. Для меня это был идеальный способ очистить все речи премьер-министра Трюдо.

Изначально я решил использовать Selenium, который позволяет пользователям управлять драйвером браузера, который может взаимодействовать с Javascript. В следующем примере кода я поручаю драйверу Chrome перебирать все статьи в списке и извлекать дату, заголовок и стенограмму речи с помощью комбинации селекторов CSS и XPATHS.

for article in article_list:
   article.click()
   
   time.sleep(3)
   
   # Getting title
   title = article.find_element_by_xpath("//h1[@class = 'field-content']")
   print(title.text)  

   # Getting date
   date = article.find_element_by_class_name("date-display-single")
   print(date.text)

   # Getting place
   place = article.find_element_by_xpath("//div[@class = 'inline-date']")
   print(place.text)

   # Getting speech
   speech_div = browser.find_elements_by_xpath("//span[@lang = 'EN-CA']")
   
   for p in speech_div:
      print(p.text)

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

Вместо этого я решил применить метод очистки AJAX. Во-первых, я заметил, что каждая речь была загружена с использованием AJAX с уникальным идентификатором. Во-вторых, я обнаружил, что этот идентификатор можно найти в тизере расширяемого блока div. Используя идентификатор из тизера, я программно загрузил все выступления с помощью библиотеки запросов, проанализировал текст на наличие важной информации с помощью BeautifulSoup и сохранил всю информацию в базе данных MongoDB. Ниже приведена часть скрипта парсинга AJAX, который использует запросы AJAX для скачать речь:

def fetch_speech_details(speech_id: str) -> str:

    # AJAX requests link. Replaced ID with speech_id collected from teaser
    url = 'https://pm.gc.ca/eng/views/ajax?view_name=news_article&view_display_id=block&view_args={id}'
    url = url.format(id = speech_id)

    # Get the speech
    res = requests.get(url, headers=headers)
    res.raise_for_status()

    # Convert to proper form using BeautifulSoup
    data = res.json()
    html = data[1]['data']
    soup = BeautifulSoup(html, 'html.parser')

    # Select the speech content
    body = soup.select_one('.views-field-body')
    speech_text = body.get_text()

    return str(speech_text)

Очистка

Я предпринял несколько шагов, чтобы очистить наскобленные речи:

  • Токенизация: токенизация относится к практике разделения текста на части, называемые токенами. В этом конкретном проекте я токенировал речи в отдельные слова, но вместо этого я мог бы токенизировать речь в предложения. Кроме того, я преобразовал каждый токен в нижний регистр, чтобы обеспечить единообразие. Это было сделано с помощью библиотеки spacy.

  • ngram: ngram относится к последовательности из n элементов в образце текста. В этом проекте я экспериментировал с преобразованием вышеуказанных токенов в униграммы (одно слово), биграммы (два слова) и триграммы (три слова). Функция ngram была доступна в библиотеке NLTK.
  • Лемматизация: этот процесс удаляет флексивные концы слова, чтобы прийти к базе или лемме. Например, «изучал» и «учился» имеет лемму «учиться». Лемматизируя слова, мы можем найти основу и уменьшить вариативность между предложениями. Также важно отметить, что лемматизация не отрубает грубо концы глаголов (также известное как основание); скорее, он использует правила грамматики, чтобы прийти к основному слову. На этом этапе использовалась функция лемматизатора WordNet в библиотеке NLTK.

  • Удаление стоп-слов: в любом языке есть чрезвычайно распространенные слова, которые не придают предложениям никакого дополнительного значения. Например, предложение «Билли ел блины перед тем, как пойти в школу», можно преобразовать в бесконечное предложение «Билли ел блины перед тем, как пойти в школу». Удаление игнорируемых слов помогает упростить вычисления для более поздних моделей, таких как набор слов, при сохранении значения предложения. Удаление стоп-слов производилось с помощью библиотеки NLTK.

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

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

Вместо этого я использовал библиотеку VaderSentiment, которая любезно предоставляет API для автоматической оценки настроений. Сложные баллы давались вместе с положительными, нейтральными и отрицательными баллами; составной балл помогает определить общую тональность отрывка.

Вот пример использования кода для анализа настроений в речи:

# Getting sentiment score of each speech
def sentiment_score(speech):
    # Initializing analyzer object
    analyzer = SentimentIntensityAnalyzer()

    # Outputting and returning speech sentiment score
    score = analyzer.polarity_scores(speech)
    print("Speech: ", speech)
    print("Score: ", score)

    return score

Тематический анализ

Тематический анализ состоял из нескольких шагов, так как мне пришлось обучить свою собственную модель, а не использовать API:

  • Создание модели набора слов: алгоритмы машинного обучения имеют один общий недостаток - модели могут работать только с векторами или сериями чисел. Конечно, это не естественное представление текста, поэтому преобразование текста в векторы признаков является неотъемлемой задачей обработки естественного языка. Один из способов преобразования текста в векторы признаков - использование модели набора слов. Этот механизм требует нескольких шагов. Во-первых, необходимо создать корпус или словарь; В своем проекте я использовал всю коллекцию речевых знаков премьер-министра Трюдо в качестве словаря. Во-вторых, модель должна записывать все различные типы словаря в словарь и давать каждому слову определенный идентификатор. Наконец, каждая речь должна быть оценена на основе словарного запаса. Оценка каждой речи для этого проекта была относительно простой задачей: я просто подсчитал количество вхождений каждой комбинации идентификатора слова. Вот простая диаграмма, объясняющая создание модели набора слов.

  • Создание модели скрытого распределения Дирихле (LDA): модель LDA - одна из наиболее полезных тематических моделей, существующих в настоящее время. По сути, LDA определяет вероятность принадлежности документа к определенной теме на основе вероятности появления определенных текстовых последовательностей в каждой теме. Например, если слова защита окружающей среды и трубопроводы с высокой вероятностью встречаются в теме 1 и если в документе будет много случаев защиты окружающей среды и трубопроводов, то документ с высокой вероятностью будет документ темы 1. Для более подробного и красивого объяснения работы модели LDA, пожалуйста, посетите эту статью. В моем проекте эта модель была создана на основе модели мешка слов для всех выступлений.

  • Прогнозы: когда модель, наконец, построена, мы можем пропустить каждую речь через модель набора слов, чтобы преобразовать речь в вектор признаков и спрогнозировать тему с помощью LDA. В отличие от k-средних, LDA дает вероятность того, что документ принадлежит определенной теме, поэтому он определенно более нечеткий, чем k-среднее. Это означает, что выходные данные прогноза представляют собой список тем и их соответствующие вероятности.

Наконец, все настроения и темы хранились в базе данных MongoDB.

Результаты и анализ

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

Несмотря на то, что они выглядят привлекательно, эти облака слов являются отличным источником анализа. Например, последнее слово wordcloud дает нам несколько идей:

  • Акцент на канадском происхождении: конечно, как премьер-министр Канады, количество упоминаний «Канады» или «канадца» не вызывает удивления.
  • Коренные народы: учитывая, что история взаимодействия Канады с коренными народами была связана с трагедией и политикой примирения премьер-министра Трюдо, частота употребления терминов, связанных с коренными народами, указывает на то, что Трюдо сосредоточил многие из своих усилий на попытке исправить ошибки прошлого. .
  • Time: интересно отметить, что выступления Трюдо указывают на то, что его политика больше ориентирована на «сегодня» и «прошлое» («годы назад»), чем на будущее, особенно с учетом того, что Трюдо проводил кампанию на платформе оптимизма в отношении будущего. Его официальные речи и предвыборные обещания могут не совпадать, как предполагалось!

Я также посмотрел на количество жетонов для каждой речи в среднем. Вот гистограмма количества жетонов для всех выступлений (ось абсцисс - количество жетонов, ось ординат - количество выступлений)

Это распределение примерно нормальное, в среднем около 1750 слов. При средней скорости 150 слов в минуту это означает, что среднее время выступления составляет примерно 12 минут. Для большинства официальных речей такая длина была бы приемлемой, но предвыборные выступления определенно были бы короче - примерно 5–7 минут.

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

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

В целом стиль речи Трюдо отражает его предвыборные обещания оптимизма в правительстве.

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

Здесь следует отметить несколько моментов:

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

Последней важной частью анализа стали темы выступлений Трюдо. Из 5-топической конструкции LDA мой скрипт вывел следующие темы:

Темы 0–2, кажется, больше связаны с темой коренных народов, тема 3 больше связана с темой канадской идентичности, а тема 4 связана с защитой окружающей среды.

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

В целом результаты были очень успешными.

Заключение

Это был один из самых сложных проектов, за которые я взялся, и благодаря ему я многому научился. Обработка естественного языка и LDA были терминами, о которых я ничего не знал до этого проекта; Однако анализ выступлений премьер-министра помог мне расширить свои знания в этой области машинного обучения.

Кроме того, я изучил множество новых технологий и навыков, от таких пакетов, как NLTK, до управления нереляционными базами данных через MongoDB. Если честно, это технологии, о которых я бы никогда не узнал, если бы не такой глубокий проект.

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

Поскольку на завершение этого проекта оставался всего месяц, расстановка приоритетов вынудила меня отказаться от следующих компонентов, которые продвинули бы этот проект на шаг вперед:

  • Создайте один скрипт для запуска всех функций одной командой
  • Очистите больше выступлений: по какой-то причине моему сценарию не удалось очистить более 10 выступлений. Это может быть из-за кнопки «Показать еще», которая привлекает больше выступлений.
  • Больше экспериментируйте с биграммами и триграммами: меня действительно интересовало, как биграммы и триграммы повлияют на точность моей модели LDA, поэтому я продолжу экспериментировать с ними.

В целом, это был довольно интересный и сложный проект, над которым я буду продолжать экспериментировать. Исходный код проекта можно найти здесь, если вы хотите поэкспериментировать с моим анализом. Голосуйте за всех в Канаде в октябре!