欢迎你们前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~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),第一时间获取更多海量技术实践干货哦~