Для этой лабораторной работы я выбрала датасет с Kaggle, который содержит в себе описания сюжетов фильмов, собранные с Википедии. Изначальный датасет включает в себя данные о 35,000 фильмах, но так как некоторые иностранные фильмы содержали слова на других языках, я решила отфильтровать датасет и оставить только американские фильмы. Так же я ограничила выборку только фильмами после 2000 года (исключительно по причине того, что мой компьютер не тянул полный датасет).
df <- read_csv("~/labs and practice/wiki.csv",
col_types = cols(`Release Year` = col_number()))
df <- df %>% filter(Genre != "unknown") %>% filter(`Origin/Ethnicity` == "American") %>% filter(`Release Year` > 2000) %>% select(-'Wiki Page', -Cast, -Director, -`Release Year`) %>% arrange(Genre)
head(df)
После проделанных операций в нашей выборке осталось 3557 фильмов. Далее я провожу токенизацию, выделяя отдельные слова и лемматизирую их, потому что в анализе описаний фильмов различные формы слов мне не так интересны, как общие темы.
Я так же удалила стоп-слова и цифры, так как считаю, что в данной работе они не дадут нам каких-либо важных инсайтов. В итоге получилось 1,184,263 слова.
movie_words <- df %>% unnest_tokens(words, Plot)
stop <- tibble(word = stopwords("en"))
movie_words <- movie_words %>% anti_join(stop, by = c(words="word")) %>%
filter(!str_detect(words, "[0-9]"))
movie_words$words <- movie_words$words %>% str_trim(side = "both")
movie_words$words <- lemmatize_words(movie_words$words)
head(movie_words)
В качестве фокусного корпуса я беру фильмы в жанре хоррор, в таблице ниже можно увидеть количество слов в фокусном и в референсном корпусах.
mw <- movie_words %>% mutate(id = ifelse(Genre == "horror", "focus", "reference")) %>% select(id, words)
table(mw$id)
##
## focus reference
## 88402 1095861
Первым делом я использую алгоритм simple maths Адама Килгариффа (+n). Это самый простой алгоритм, считающий частотность слов в двух корпусах.
mw.freq <- mw %>%
group_by(id) %>%
count(words) %>%
spread(id, n, fill=0) %>%
arrange(desc(focus+reference))
m.ipm <- mw.freq
m.ipm %>% mutate(f.ipm = (focus+1)/sum(focus+1)*10000, r.ipm = (reference+1)/sum(reference+1)*10000) %>% mutate(sm = f.ipm/r.ipm) %>% arrange(desc(sm)) %>% head
m.ipm %>% mutate(f.ipm = (focus+10)/sum(focus+10)*10000, r.ipm = (reference+10)/sum(reference+10)*10000) %>% mutate(sm = f.ipm/r.ipm) %>% arrange(desc(sm)) %>% head
m.ipm %>% mutate(f.ipm = (focus+100)/sum(focus+100)*10000, r.ipm = (reference+100)/sum(reference+100)*10000) %>% mutate(sm = f.ipm/r.ipm) %>% arrange(desc(sm)) %>% head
К сожалению, этот алгоритм не даёт нам никаких интересных результатов, потому что все предоставленные слова - это имена собственные. Например, самое характерное слово Merrin - это фамилия священника из фильма Exorcist: The Beginning (2004), Creeper - имя маньяка из Jeepers Creepers (2001), Lucian - имя вампира из Underworld (2003) Fenton - имя главного героя фильма Frailty (2001), Lestat - снова имя вампира из Queen of the Damned (2001).
Результаты это весьма ожидаемые, потому что этот алгоритм основывается только на частотности, а в описании сюжета одного фильма имена героев мелькают очень много раз, поэтому алгоритм считает их характерными для всего фокусного корпуса. Во всех трёх таблицах есть только одно слово, выделяющееся среди других, и это Heidi, так как оно встречается целых 15 раз и в референсном корпусе, в то время как все остальные слова встречаются там только 0-1 раз. Посмотрим, в каких фильмах оно упоминается, их жанры и количество упоминаний слова.
movie_words %>% filter(words == "heidi") %>% group_by(Title, Genre) %>% tally()
Я проверила все фильмы и во всех кого-либо из персонажей зовут Heidi. Ничего интересного, кажется, это просто популярное имя!
Дальше мы выделим характерную лексику методом log-likelyhood.
g2 = function(a, b) {
c = sum(a)
d = sum(b)
E1 = c * ((a + b) / (c + d))
E2 = d * ((a + b) / (c + d))
return(2*((a*log(a/E1+1e-7)) + (b*log(b/E2+1e-7))))
}
m.ll <- m.ipm %>%
mutate(g2 = g2(focus, reference)) %>%
arrange(desc(g2))
head(m.ll)
Этот же алгоритм чувствителен к частотным словам, поэтому тут слова гораздо более распространённые, чем в предыдущем алгоритме.
Тут уже можно заметить более интересные результаты, потому что мы видим слова, которые вполне можно ожидать в описании фильмов в жанре “хоррор”. Среди них названия страшных мифических существ (vampire, demon, creature, dracula, ghost) и, конечно же, слова, связанные с убийствами (kill, body, blood, corpse, attack).
Самое интересное для меня наблюдение - это слова, связанные с местами (house, basement, room). Судя по всему, локации в описаниях фильмов ужасов имеют более важную роль, чем в фильмах других жанров, и я предполагаю, что они нужны для указания на место убийства, либо, в случае мистических фильмов, на место обитания призраков.
m.p <- mw.freq %>%
mutate(p.x_y = focus/sum(focus), p.x = (focus+reference)/(sum(focus)+sum(reference)))
m.pmi <- m.p %>%
mutate(m.pmi = log2(p.x_y/p.x)) %>%
arrange(desc(m.pmi))
m.pmi
Результаты применения PMI можно сравнить с результатами Simple Maths, потому что он тоже выдаёт имена собственные, которые нам не интересны. Thomasin - имя главной героини The Witch (2015), Chromeskull - серийный убийца из одноимённого фильма и так далее. Разница в том, что ВСЕ результаты PMI ни разу не встречаются в референсном корпусе, так как этот алгоритм очень чувствителен к малочастотным словам и именно поэтому он показывает нам слова, которые есть исключительно в нашем фокусном корпусе.
Чтобы хоть как-то компенсировать эти результаты, я решила отфильтровать результат так, чтобы количество упоминаний слова в референсном корпусе было больше 0, но, увы, мы всё равно остались только с именами собственными.
m.pmi %>%
filter(reference>0) %>%
head(100) %>%
arrange(desc(focus+reference))
m.counts <- mw %>% count(id, words, sort=TRUE)
m.lo <- m.counts %>%
bind_log_odds(id, words, n)
m.lo %>% filter(id == "focus") %>%
arrange(desc(log_odds_weighted)) %>% head(30)
В результата применения Weighted log-odds у нас получились результаты, схожие с Log-likelyhood. Мы точно так же видим слова, связанные с убийствами и слова, связанные с мистикой. Разница заключается в том, что тут прибавились такие слова, как find, see, take, go, leave, try, tell, escape и можно заметить, что все они являются глаголами. Это довольно интересно, и можно предположить, что описания хоррор-фильмов больше сфокусированы на действиях, чем другие жанры. Так же можно увидеть слова “group”, “late,”car“,”house" и их появление не удивляет, так как у меня в голове сразу появляется картина типичного тропа хоррор-фильмов, где группа друзей едет на отдых, поздно ночью у них перестаёт работать машина и им приходится идти просить помощи в страшный дом, который ни разу не подозрительно стоит один посреди тёмного леса.
Как можно заметить из результатов, алгоритмы Log-likelyhood и Weighted log-odds оказались для нас самыми интересными и информативными и действительно выделили лексику, характерную для фильмов жанра хоррор. Причина, скорее всего, заключается в том, что они не так чувствительны к малочастотным словам, как Simple maths и PMI. Вероятно, на других данных Simple maths и PMI показали бы очень редкие и интересные слова, но из-за специфики моих данных, где очень часто встречались имена собственные, они не показали никаких интересных результатов.