歡迎你們前往騰訊雲+社區,獲取更多騰訊海量技術實踐乾貨哦~html
本文來自 雲+社區翻譯社,做者 HesionBlack
最近我從馬克·裏德爾 那拿到了很棒的天然語言方面的數據集 :從WIKI下載了112000個故事做品的情節。其中包括了書籍、電影、電視劇集、視頻遊戲等有「情節」的任何內容。python
這爲我定量分析故事結構提供了一個很好的契機。在這篇文章中,我將會進行一個簡單的分析來檢驗在故事中的特定情節上,哪些詞會頻繁出現,好比一些提示了故事開端開始,中間情節或結局的詞。git
根據我對文本挖掘的習慣,我將使用Julia Silge和我在去年開發的tidytext軟件包。若是你想要了解更多相關知識,請參閱咱們的這本在線書Text Mining with R: A Tidy Approach,它將很快被O'Reilly出版了。我將爲您提供部分代碼,以便您能夠繼續跟上個人思路。爲了保持文章簡潔,關於可視化部分的代碼我基本都沒貼出來。但全部的文章和代碼均可以在GitHub上找到。github
我從GitHub上下載並解壓縮了plots.zip文件。而後咱們將這些文件讀入R,而後將它們與dplyr
使用結合。微信
library(readr) library(dplyr) # Plots and titles are in separate files plots <- read_lines("~/Downloads/plots/plots", progress = FALSE) titles <- read_lines("~/Downloads/plots/titles", progress = FALSE) # Each story ends with an <EOS> line plot_text <- data_frame(text = plots) %>% mutate(story_number = cumsum(text == "<EOS>") + 1, title = titles[story_number]) %>% filter(text != "<EOS>")
而後,咱們可使用tidytext將情節整理爲一個簡潔的結構,一個詞一行。app
library(tidytext) plot_words <- plot_text %>% unnest_tokens(word, text)
plot_words
## # A tibble: 40,330,086 × 3 ## story_number title word ## <dbl> <chr> <chr> ## 1 1 Animal Farm old ## 2 1 Animal Farm major ## 3 1 Animal Farm the ## 4 1 Animal Farm old ## 5 1 Animal Farm boar ## 6 1 Animal Farm on ## 7 1 Animal Farm the ## 8 1 Animal Farm manor ## 9 1 Animal Farm farm ## 10 1 Animal Farm summons ## # ... with 40,330,076 more rows
該數據集包含了超過4000萬個單詞,112000個故事。機器學習
約瑟夫坎貝爾提出了名爲「hero‘s journey」的分析方法,他認爲每一個故事都有一致的結構。不管你是否對他的理論買帳,假如一個故事在一開頭就是高潮開始的或者到告終束卻引入了新角色,你可能也會以爲這是很使人詫異的。ide
這種結構能夠用單詞的量化結構來表現-- 有些詞彙應該被指望在開始時出現,而一些詞詞則在應該在結尾出現。學習
一個簡單的測量方法,咱們將記錄每一個單詞的位置的中值,同時也記錄它出現的次數。ui
word_averages <- plot_words %>% group_by(title) %>% mutate(word_position = row_number() / n()) %>% group_by(word) %>% summarize(median_position = median(word_position), number = n())
咱們對在少數情節出現而且出現頻率比較小的詞語不感興趣,因此咱們將篩選出至少出現了2500次的單詞,並只對他們進行分析。
word_averages %>% filter(number >= 2500) %>% arrange(median_position)
## # A tibble: 1,640 × 3 ## word median_position number ## <chr> <dbl> <int> ## 1 fictional 0.1193618 2688 ## 2 year 0.2013554 18692 ## 3 protagonist 0.2029450 3222 ## 4 century 0.2096774 3583 ## 5 wealthy 0.2356817 5686 ## 6 opens 0.2408638 7319 ## 7 california 0.2423856 2656 ## 8 angeles 0.2580645 2889 ## 9 los 0.2661747 3110 ## 10 student 0.2692308 6961 ## # ... with 1,630 more rows
例如,咱們能夠看到,「fictional」這個詞大約用了2700次,其中半數出如今故事的前12% - 這代表這個詞與開端有很大的關係。
下圖展現了與故事開頭和結尾關聯最大的一些詞。
與開頭相關的詞時常是描述一些設定:「這個故事主角(protagonist),是一個年輕(young),富有(weathy)的 19世紀(century)的學生(student),最近(rencently)從在美國加利福尼亞州洛杉磯編造的大學(university College)畢業。它們大部分都是名詞和形容詞,能夠用來描述並限定一我的,一個地點或者一個時期。
相比之下,在故事結尾處的單詞就充滿情感!有些詞自己就有結尾的意思。好比「ending」和「final」,但也有一些動詞反映了激烈刺激的情節,好比「英雄向惡棍射擊(shoots)並衝向(rushes)女主角,並道歉(apologizes)。兩人團聚(reunited),他們吻了(kiss)。「
中值的方法爲咱們提供了一個有用的彙總統計信息,讓咱們仔細研究下統計信息的內容。首先,咱們將每一個故事分紅幾個十分位數(前10%,後10%等),並計算每一個單詞在每一個十分位數內的次數。
decile_counts <- plot_words %>% group_by(title) %>% mutate(word_position = row_number() / n()) %>% ungroup() %>% mutate(decile = ceiling(word_position * 10) / 10) %>% count(decile, word)
上述工做使咱們能夠經過繪製不一樣單詞在不一樣情節的位置中的頻率分佈。咱們想看看哪些單詞集中在開始/結束的:
沒有任何單詞會中只在故事的開始或結束。像「高興地(happily)」,在全文都穩定出現,但在最後結尾頻率飆升(「今後他們過上幸福快樂(happily)的生活」)。其餘的詞,如「真相(truth)」或「道歉(apologize)」,在故事情節發展的過程當中頻率不斷上升,這很合理。一個角色一般不會在故事開始時就「道歉(apologize)」或「意識到真相(realize the truth)」。相似的,「wealthy」這類描述設定的詞出現頻率會逐漸降低,就像劇情發展到後面就越不可能引入新的角色同樣。
上圖種有一個有趣特徵,大多數單詞出現頻率最高的時候是在開始或結束時,但在90%的點上,像「grabs」, 「rushes」, 和 「shoots」這樣的詞在故事的90%部分最常出現,說明故事的高潮通常在這裏。
受到對出如今故事高潮時出現的單詞的分析的啓發,咱們能夠觀察哪些單詞出如今故事情節的中間部分,而不是一直盯着開頭和結尾不放。
peak_decile <- decile_counts %>% inner_join(word_averages, by = "word") %>% filter(number >= 2500) %>% transmute(peak_decile = decile, word, number, fraction_peak = n / number) %>% arrange(desc(fraction_peak)) %>% distinct(word, .keep_all = TRUE) peak_decile
## # A tibble: 1,640 × 4 ## peak_decile word number fraction_peak ## <dbl> <chr> <int> <dbl> ## 1 0.1 fictional 2688 0.4676339 ## 2 1.0 happily 2895 0.4601036 ## 3 1.0 ends 18523 0.4036603 ## 4 0.1 opens 7319 0.3913103 ## 5 1.0 reunited 2660 0.3853383 ## 6 0.1 protagonist 3222 0.3764742 ## 7 1.0 ending 4181 0.3721598 ## 8 0.1 year 18692 0.3578536 ## 9 0.1 century 3583 0.3530561 ## 10 0.1 story 37248 0.3257356 ## # ... with 1,630 more rows
故事的每一個十分位數(起點,終點,30%點等)都有一次單詞出現的頻率很高。哪些詞更能表明這些十分位呢?
咱們觀察到,開頭和結尾的高頻詞相對固定。例如,「fictionnal」一詞出如今故事的前10%。中間部分的詞彙分佈的相對分散(好比,在該部分中出現的比例爲14%,而不是預期的10%),但它們仍然是故事結構中頗有意義的詞彙。
咱們能夠把其中表明性強的單詞的完整趨勢繪製出來看看。
試着分析上圖的24個詞,咱們的主人公被「attracted」, then 「suspicious」, followed by 「jealous」, 「drunk」, and ultimately 「furious」. A shame that once they 「confront」 the problem, they run into a 「trap」 and are 「wounded」.若是你忽略掉哪些重複的詞和語法的確實,你能夠發現整個故事的趨勢能夠用這些關鍵詞複述出來。
咱們關於故事情節中不斷上升的緊張局勢和衝突的這一假設,獲得了證明。能夠用情感分析來發現每一個故事不一樣10分位的平均情感得分。
decile_counts %>% inner_join(get_sentiments("afinn"), by = "word") %>% group_by(decile) %>% summarize(score = sum(score * n) / sum(n)) %>% ggplot(aes(decile, score)) + geom_line() + scale_x_continuous(labels = percent_format()) + expand_limits(y = 0) + labs(x = "Position within a story", y = "Average AFINN sentiment score")
情節描述在故事中的每一個部分都計算出了負AFINN分值(這是頗有意義的,由於故事是聚焦於矛盾的)。但開頭相對平緩一點,而後矛盾開始逐步凸顯出來,在80-90%的高潮時。而後一般會有一半的結束,一半包含「快樂(happily)」,「救助(rescues)」和「團聚(reunited)」等詞彙,致使得分又變高了。
總而言之,若是咱們必須總結出人類撰寫的平均的故事結構,那麼大體都是「事情會變得愈來愈糟,直到最後一分鐘纔出現起色,變得愈來愈好」這樣的狀況。
這是對故事情節的簡單的分析(須要深刻挖掘的例子,參見這些研究),並無獲得齊全的信息,(除了角色可能在故事中期被灌醉。咱們如何深刻洞悉這些情節)
經過本文我但願你能掌握這些在大型文本據數集上快速量化分析(計數,採用中位數)故事結構的能力。接下來的文章中我會深刻挖掘這些情節,來看看咱們還能獲得哪些信息。
問答
如何使用樣本數據或Web服務對NLTK python進行情感分析?
相關閱讀
豆瓣電影數據分析和可視化
使用snownlp進行評論情感分析
拓撲數據分析在機器學習中的應用
此文已由做者受權騰訊雲+社區發佈,原文連接:https://cloud.tencent.com/dev...
歡迎你們前往騰訊雲+社區或關注雲加社區微信公衆號(QcloudCommunity),第一時間獲取更多海量技術實踐乾貨哦~