web analytics

Анализ текста речей на съезде президента США 2024 года

Может ли актуарий/математик/аналитик данных сказать что-либо объективное и основанное на данных о президентской кампании в США 2024 года?

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

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

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

      Я также подсчитал наиболее часто встречающиеся слова кандидатов, исключив такие стоп-слова, как «a», «and», «the» и т. д., которые не несут в себе много полезной информации:

Наиболее часто встречающиеся слова

    Я подсчитал статистику таких вещей, как средняя длина предложения и средняя длина слова:

Сводная статистика

      Этот блог — моя попытка провести объективный и ориентированный на данные анализ двух кандидатов в президенты из их речей на съездах. Это текстовый анализ их речей. Текстовый анализ — это раздел анализа данных, который берет неструктурированные текстовые документы, разбивает их на предложения и слова и пытается найти какой-то смысл. Текстовый анализ используется маркетологами для оценки мнений клиентов, полицейскими управлениями для отслеживания потенциальной или фактической преступной деятельности, исследователями для оценки таких вещей, как то, действительно ли Шекспир написал все приписываемые ему пьесы, и какие песни Beatles в основном были написаны Джоном, а какие — Полом, и многими другими.

      Это задумано как объективный анализ. Я не пытаюсь выставить ни одного из кандидатов в хорошем или плохом свете. Я использовал те же самые методы анализа текста в других проектах, таких как анализ «Гамлета» , анализ рассказов и анализ твитов ведущего радио-ток-шоу в Twitter.

      Для Трампа и Харриса я начал с расшифровки их речей на съезде. Я считаю, что расшифровки — это их устные расшифровки, а не письменные расшифровки, основанные на их самых первых нескольких предложениях. Я использовал различные компьютерные пакеты на R, такие как tm и tidytext, чтобы разбить документы на отдельные предложения, слова и символы. Я руководствовался работами Силге и Робинсона в Text Mining with R и Уильямса в Data Science Desktop Survival Guide .

      Ниже приводится краткое изложение и сравнение токенизации речей, повторенное ранее.

      Очевидно, Трамп говорил намного дольше, чем Харрис, поэтому у него было намного больше общего количества слов. У Харрис была большая средняя длина предложения (18,06 против 10,41), но они оба были близки по средней длине слова и среднему количеству слогов в слове. Их числовые баллы по Флешу были примерно равны — это мера уровня обучения, необходимого для понимания текста. У Харрис был больший процент уникальных или отличающихся слов в ее речи, чем у Трампа (22% против 12%). У Трампа был больший процент отрицательных слов, чем у Харрис (43% против 37%), о чем я расскажу ниже.

      Анализ настроений ia анализ текста для определения его эмоционального тона. Эксперты по лингвистике создали словари, которые связывают большой список слов с восемью эмоциями (гнев, ожидание, отвращение, страх, радость, печаль, удивление и доверие), а также отрицательными и положительными чувствами. Например, слово «ache» ассоциируется с грустью. Некоторые слова имеют более одной эмоции; например, «admirable» ассоциируется как с радостью, так и с доверием. Кроме того, некоторые слова имеют либо отрицательные, либо положительные ассоциации.

      В анализе настроений есть некоторые ограничения. Словарь настроений не распознает сарказм, и я ограничиваю свой анализ отдельными словами, поэтому я не выделяю отрицание (например, «не дорого») или другие случаи, когда эмоция требует нескольких слов. Вывод из графика распределения настроений заключается в том, что кандидаты на удивление похожи в большинстве этих эмоций. Самые большие различия в том, что у Трампа большая часть его слов классифицируется как гнев и негатив, чем у Харриса.

Наиболее часто встречающиеся положительные и мегативные слова

      Частые положительные слова Трампа включают «любовь», прилагательные «красивый» и «замечательный», а также «деньги». Его отрицательные слова включают «налог», «вторжение», «инфляция», «война», «незаконный» и «преступление».

      Часто употребляемые положительные слова Харрис включают «свобода», «любовь», «возможность» и «вперед». Отрицательные слова включают «налог», «принуждение», «злоупотребление» и «аборт». Интересно, что «мать» — это и положительное, и отрицательное слово, как и «голосование». (Я перепроверила словарь настроений, чтобы подтвердить это.)

      У Трампа процент негативных слов (негативных, деленных на позитивные плюс негативные) больше, чем у Харрис (43% к 37%). Эти позитивные и негативные списки, похоже, соответствуют моим воспоминаниям об их речах.

Наиболее часто встречающиеся слова

      Частота слов дает некоторое представление о том, что важно для каждого кандидата. Неудивительно, что оба кандидата часто использовали такие слова, как «Америка», «американцы», «страна», «нация» и «граница». Трамп использовал такие прилагательные, как «красивый» и «невероятный». Харрис много времени уделила разговорам о Трампе, а также о своей матери. Харрис часто использовала «средний», «класс», «женщины» и «закон».

Распределение размеров слов

Распределение слогов в слове

      Распределение размеров слов и количества слогов в слове у обоих кандидатов довольно схоже.

Заключительные мысли

      Трудно оставаться равнодушным к президентским выборам в США 2024 года. У вас есть свое мнение, а у меня свое. Многое из того, что говорят кандидаты, — это их мнение или их план в случае избрания, и эти вещи мы не можем проверить.

      Некоторые вещи, которые кандидаты говорят как факты, излагаются таким образом, что они открыты для интерпретации. Хорошим примером является: «Сегодня вы находитесь в лучшем (или худшем) финансовом положении, чем четыре года назад». Я могу выбрать одну меру, собрать некоторые данные и показать, что я в лучшем положении; или я могу выбрать совершенно другую меру, собрать некоторые данные и показать, что я в худшем положении.

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

      Анализ текста — популярный метод анализа данных, и я надеюсь, что мне удалось составить объективное представление о кандидатах.

      Ниже приведен мой код R:

# Речь Трампа на съезде, 19 июля 2024 г.
# https://www.nytimes.com/2024/07/19/us/politics/trump-rnc-speech-transcript.html

# Речь Харриса на съезде, 23 августа 2024 г.
# https://singjupost.com/full-transcript-kamala-harriss-2024-dnc-speech/?singlepage=1

library(tidytext)
library(tm)
library(dplyr)
library(nsyllable)
library(SnowballC)
library(ggplot2)
library(forcats)
library(ggpubr)

speaker <- readline(prompt = «Введите Trump или Harris: «)
if (speaker == “Trump” | speaker == “Harris”) print(speaker) else print(“Неверный ввод”)
trump_file <- «C:/Users/Jerry/Desktop/Harris_Trump/trump_convention_speech.txt»
harris_file <- «C:/Users/Jerry/Desktop/Harris_Trump/harris_convention_speech.txt»
textfile <- ifelse(speaker==»Trump», trump_file, harris_file)
textfile <- readLines(textfile)
text_df <- data.frame(line = 1:length(textfile), text=textfile)
names(text_df)[2] <- «text»

docs <- Corpus(VectorSource(text_df$text))
docs <- tm_map(docs, content_transformer(tolower))
docs <- tm_map(docs, removeNumbers)
docs <- tm_map(docs, removePunctuation, ucp=TRUE)
docs <- tm_map(docs, stripWhitespace)
inspect(docs[1:8])

custom_colors <- c(«#1f77b4», «#ff7f0e», «#2ca02c», «#d62728», «#9467bd»,
      «#8c564b», «#e377c2», «#7f7f7f», «#bcbd22», «#17becf»,
      «#6a3d9a», «#ff9e1b», «#f6c6c7», «#8dd3c7», «#ffffb3»,
      «#bebada», «#fb8072», «#80b1d3», «#fdb462», «#b3e2cd»,
      «#ccebc5»)

common_theme <- theme(
      legend.position=»NULL»,
      plot.title = element_text(size=15, face=»bold»),
      plot.subtitle = element_text(size=12.5, face=»bold»),
      axis.title = element_text(size=15, face=»bold»),
      axis.text = element_text(size=15, face=»bold»),
      legend.title = element_text(size=15, face=»bold»),
      legend.text = element_text(size=15, face=»bold»))

docs_df <- data.frame(text = sapply(docs, as.character)) # Преобразовать корпус в data.frame
wordfile <- unnest_tokens(docs_df, word, text, token = «words»)
wordfile %>% count(word, sort=TRUE)
wordcountfile <- mutate(wordfile, numbchars = nchar(word)) # символов в слове
long1 <- wordcountfile[which(wordcountfile$numbchars == max(wordcountfile$numbchars)),1] # самое длинное слово long2 <- wordcountfile[which(wordcountfile$numbchars == max(wordcountfile$numbchars)),2]
numberchars <- sum(wordcountfile$numbchars)
numberwords <- sum(count(wordcountfile, word, sort=TRUE)$n) # нет. слова
avgcharperword <- round(numberchars / numberwords, digits=2)
sentencefile <- unnest_tokens(text_df, sentence, text, token = «sentences»)
sentencecount <- sum(count(sentencefile, sentence, sort=TRUE)$n)
avgwordpersent <- round(numberwords / sentencecount,2)

wordcountdist <- wordcountfile %>% count(numbchars)
wordcountdist$numbchars <- as.factor(wordcountdist$numbchars)
title <- paste(speaker, «- Распределение размера слова»)
subtitle <- paste(«Самое длинное слово: «, long1, long2, «символы»)
ggplot(wordcountdist, aes(numbchars, n, fill=numbchars)) +
      geom_bar(stat=”identity”, position = “dodge”, width=0.5) +
      labs(title=title, subtitle=subtitle) +
      xlab(“количество символов в слове”) + ylab(“”) +
      scale_fill_manual(values ​​= custom_colors) +
      theme(legend.position = “none”) +
      common_theme

syls <- nsyllable(wordfile$word, language = «en»)
syls[which(wordfile$word == “jd”)] <- 2 # используется, потому что nsyllable сгенерировал здесь ошибку
syls[which(wordfile$word == “nd”)] <- 1 # используется, потому что nsyllable сгенерировал здесь ошибку
syls[which(wordfile$word == “st”)] <- 3 # s/b 21st; используется, потому что nsyllable сгенерировал здесь ошибку
syls[which(wordfile$word == “gasolinepowered”)] <- 5 # используется, потому что nsyllable допустил здесь ошибку
long2 <- min(syls[(syls == max(syls, na.rm=TRUE))], na.rm=TRUE)
w <- min(which(syls == long2))
long1 <- wordfile$word[w]
avgsylperword <- round(sum(syls)/numberwords, digits = 2)
avgsylperword
syls <- data.frame(syls) %>% count(syls)
syls$syls <- as.factor(syls$syls)
colnames(syls) <- c(«syllables», «n»)
title <- paste(speaker, «- Распределение количества слогов в слове»)
subtitle <- paste(«Больше слогов: «, long1, long2, «слогов»)
ggplot(syls, aes(слогов, n, fill = слогов)) +
      geom_bar(stat=”identity”, position = “dodge”, width=0.5) +
      labs(title=title, subtitle=subtitle) +
      xlab(“количество слогов в слове”) + ylab(“”) +
      scale_fill_manual(values ​​= custom_colors) +
      theme(legend.position = “none”) +
      common_theme

# Формула легкости чтения Флеша-Кинкейда
flesch <- round(206.835 — 1.015*(numberwords/sentencecount) — 84.6*(sum(syls$n)/numberwords),2) # Легкость чтения Флеша
flesch
flesch_df <- data.frame(score = c(0,30,50,60,70,80,90,100),
      grade = c(“Выпускник колледжа”,,”Колледж”,,”10-й – 12-й класс”,,”8-й – 9-й класс”,
      “7-й класс”,,”6-й класс”,,”5-й класс”,”ниже 5-го класса”))

# Функция для поиска оценки на основе баллов; vlookup
find_grade <- function(score, flesch_df) {
  idx <- findInterval(score, flesch_df$score)
  if (idx == 0) {
   return(“below 5th grade”) # Обработка случая, когда балл ниже минимального
  } else {
   return(flesch_df$grade[idx])
  }
}

Score_to_find <- flesch
flesch_grade <- find_grade(score_to_find, flesch_df)
flesch_grade

# удалить стоп-слова
docs_df <- data.frame(text = sapply(docs, as.character)) # Преобразовать корпус в data.frame
wordfile <- unnest_tokens(docs_df, word, text, token = «words»)
stop_words <- data.frame(tidytext::stop_words) # больше слов, чем tm
my_stop_words <- data.frame(word = c(«theyre», «hes», «dont»,
   «didnt», «youre», «cant», «im», «whats», «weve», «theyve», «youve»,
   «couldnt», «wont», «youd»))
wordfile <- anti_join(wordfile, stop_words)
wordfile <- anti_join(wordfile, my_stop_words)

wordfreq <- wordfile
wordfreq <- count(wordfreq, word, sort=TRUE) # частота слова без стоп-слов
wordfreqdf <- data.frame(wordfreq)

unique_words <- nrow(wordfreq)
part_unique_words <- round(unique_words / numberwords, digits=2)
wordfreqdf20 <- wordfreqdf[1:21,] # Подумайте о пороговом значении
wordfreqdf20

graphtitle <- paste(speaker, «Частота слова»)
wordfreqdf20$word <- fct_reorder(wordfreqdf20$word, wordfreqdf20$n, .desc = FALSE)
ggplot(data=wordfreqdf20, aes(x=word, y=n, fill=word)) +
      geom_bar(stat=”identity”, position = “dodge”, width=0.5) +
      coord_flip() +
      common_theme +
      xlab(“”) + ylab(“Частота”) +
      ggtitle(graphtitle) +
      scale_fill_manual(values ​​= custom_colors) +
      theme(legend.position = “none”)

# настроения; обратите внимание, что мать может быть как положительной, так и отрицательной!
df1 <- data.frame(wordfile)
colnames(df1) <- «word»
df2 <- get_sentiments(«nrc»)
df3 <- merge(x=df1, y=df2, by=»word», all.x=TRUE, stringsAsFactors=FALSE)
df3 <- subset(df3, !is.na(sentiment))
table(df3$sentiment)
w <- data.frame(table(df3$sentiment))
colnames(w) <- c(«sentiment», «n»)

sentiment_colors <- c(
   «Гнев» = «красный»,
   «Предвкушение» = «зеленый»,
   «Отвращение» = «коричневый»,
   «Страх» = «фиолетовый»,
   «Радость» = «желтый»,
   «Негативный» = «серый»,
   «Позитивный» = «голубой»,
   «Грусть» = «синий»,
   «Удивление» = «розовый»,
   «Доверие» = «бирюзовый»)

title <- paste(speaker, «- Sentiment Plot»)
ggplot(w, aes(sentiment, n)) +
      geom_bar(stat = “identity”, position = “dodge”, width = 0.5, fill = sentiment_colors) +
      ggtitle(title) +
      ylab(“”) +
      common_theme +
      theme(axis.text.x = element_text(angle = 45, hjust=1))

df4 <- df3 %>% фильтр(настроение == «положительное» | настроение == «отрицательное»)
w <- with(df4, table(настроение))
neg <- w[1]
pos <- w[2]
neg_ratio <- round(w[1] / (w[1] + w[2]), digits=2)
df5 <- df4 %>% group_by(настроение) %>% count(word, sort=TRUE)
pos_freq <- df5 %>% фильтр(настроение==»положительное») %>% top_n(10, wt = n) %>% slice_head(n = 10)
neg_freq <- df5 %>% фильтр(настроение==»отрицательное») %>% top_n(10, wt = n) %>% slice_head(n = 10) # связи
pos_freq$word <- fct_reorder(pos_freq$word, pos_freq$n, .desc = ЛОЖЬ)
neg_freq$word <- fct_reorder(neg_freq$word, neg_freq$n, .desc = ЛОЖЬ)

title <- paste(speaker, «- Наиболее частые положительные и отрицательные слова»)
p1 <- ggplot(pos_freq, aes(word, n)) +
      geom_bar(stat=»identity», position=»dodge», width=0.5, fill=»darkgreen») +
      ggtitle(«Positves») +
      common_theme +
      xlab(«») +
      coord_flip()
p2 <- ggplot(neg_freq, aes(word, n)) +
      geom_bar(stat=»identity», position=»dodge», width=0.5, fill=»red») +
      ggtitle(«Negatives») +
      common_theme +
      xlab(«») +
      coord_flip()
plot <- ggarrange(p1,p2, ncol=2, nrow=1, legend=NULL)
annotate_figure(plot, top = text_grob(title,
    color=»black», face=» «жирный», размер = 14))

если (спикер == “Трамп”){
   t <- data_frame(спикер, numberwords, avgwordpersent, avgcharperword, avgsylperword, flesch, flesch_grade, part_unique_words, neg_ratio)
   вывод
   <- data.frame(
    rbind(t,h)) вывод <
    — t(вывод)
    colnames(вывод) <- c(«Трамп», «Харрис») вывод
    <- вывод[-1,]
    вывод(вывод)
}

# результаты стемминга и лемматизации не были использованы в отчете
# стемминг
wordfile <- wordfile %>%
    mutate(stem = wordStem(word)) %>%
    count(stem, sort = TRUE)

# лемматизация
df1 <- wordfile # df1 имеет столбец с именем stem
url <- «https://raw.githubusercontent.com/michmech/lemmatization-lists/master/lemmatization-en.txt»
df2 <- read.table(url, header = FALSE, sep = «\t», quote = «», stringsAsFactors = FALSE)
names(df2) <- c(«stem», «word»)
df3 <- merge(x = df1, y = df2, by = «stem», all.x = TRUE, stringsAsFactors=FALSE)

# если слова нет в словаре, то оставить слово как есть; в противном случае использовать слово с основой.
df3$word <- ifelse(is.na(df3$word), df3$stem, df3$stem)

# Конец

Источник:
https://www.r-bloggers.com/2024/08/text-analysis-of-2024-us-presidential-convention-speeches/

Оцените статью
( Пока оценок нет )

Добавить комментарий