文章目录

  • 1. 背景知识
  • 2. 准备数据
    • Python
    • R
  • 3. 数据清理
  • 4. 数据分析
  • 5. 收获

最近学会利用Python做了几个词云后,又应用NLP中情感分析,结合snownlp库完成了词云分类,做了积极和消极两类词云,效果图如下。

之后我对NLP的知识产生了兴趣,继续深挖,发现王树义老师的这个项目很符合我的口味,于是尝试撸之,下面记录过程。

1. 背景知识

情绪分析(emotional analysis)和情感分析(sentiment analysis)有相似之处。

相同之处是都是通过脚本对文本进行自动化分析,来获得情感的趋向。

不同之处情感分析的结果一般分为正向(positive)和负向(negative),而情绪分析包含的种类就比较多了。

加拿大国家研究委员会(National Research Council of Canada)官方发布的情绪词典包含了8种情绪,分别为:

  1. 愤怒(anger)
  2. 期待(anticipation)
  3. 厌恶(disgust)
  4. 恐惧(fear)
  5. 喜悦(joy)
  6. 悲伤(sadness)
  7. 惊讶(surprise)
  8. 信任(trust)

有了这些情绪的标记,可以轻松地对一段文本的情绪变化进行分析。

这个项目中,需要用到Python和R。这两种语言在目前数据科学领域里最受欢迎。Python的优势在于通用,而R的优势在于统计学家组成的社区。这些统计学家真是高产,也很酷,经常制造出令人惊艳的分析包。

这里就用Python来做前期的数据清理使得数据符合我们的要求便于处理,然后再将处理后的数据导入R的工作环境用R做情绪分析,并且把结果可视化输出。

2. 准备数据

项目中数据来源是《权利的游戏》第三季的第9集——“The Rains of Castamere”。

https://genius.com/Game-of-thrones-the-rains-of-castamere-annotated

只需要全选剧本拷贝,然后创建个txt文本文件把内容粘贴进去,现在你就有可供分析的文本了。

再将文本放入你的工作目录中。

Python

我们需要用到 Jupyter Notebook

R

我们需要用到 R studio

3. 数据清理

我们首先需要清理文本数据,完成以下这两个任务:

  1. 把与剧情正文无关的,对我们做情绪分析没有用处的内容去除,;
  2. 将数据转换成R可以直接做情绪分析的结构化数据格式,如csv格式。

(以下操作在Jupyter Notebook中完成)

首先需要导入需要的工具包,这里导入数据分析中常用包pandas和re正则包

import pandas as pd
import re

然后读取当前目录下的剧本文本。

with open("权游.txt") as f:data = f.read()print(data)

输出结果:

[Opening Credits][First scene shows the location of Casterly Rock (ancestral seat of House Lannister) on a giant map of Westeros. There are several game pieces representing different House sigils located on different parts of the map.ROBB STARK and CATELYN STARK are at a campsite, within a tent lit up by candles]
...

数据正确读入。下面我们把正文以外的文本内容去掉。即去掉开头和结尾的非剧本正文内容。

Python split()方法

  • 描述

Python split() 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串

  • 语法

split() 方法语法:

str.split(str="", num=string.count(str)).
  • 参数

str – 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。

num – 分割次数。默认为 -1, 即分隔所有。

  • 返回值

返回分割后的字符串列表。

data =data.split('[Opening Credits]')[1] # 分割后取第二个元素
data = data.split('[End Credits]')[0] # 分割后取第一个

移除了开头和结尾的多余内容后,我们来移除空行。这里我们需要用到正则表达式

re是正则的表达式,sub是substitute表示替换

举个例子:

str= “hello 11 word 11”

想11变成22

replacestr = str.replace(“11”,"22)

但是如果是inputs = “hello 123 world 345”

想把数字都替换成222

就需要用正则替换

re.sub有五个参数

re.sub(pattern, repl, string, count=0, flags=0)

其中三个必选参数:pattern, repl, string两个可选参数:count, flags

pattern

pattern,表示正则中的模式字符串。

反斜杠加数字(\N),则对应着匹配的组(matched group)

比如\6,表示匹配前面pattern中的第6个group

第二个参数:repl

repl,就是replacement,被替换,的字符串的意思。

repl可以是字符串,也可以是函数。

如果repl是字符串的话,其中的任何反斜杠转义字符,都会被处理的。

即:

\n:会被处理为对应的换行符;

\r:会被处理为回车符;

其他不能识别的转移字符,则只是被识别为普通的字符:

比如\j,会被处理为j这个字母本身;

反斜杠加g以及中括号内一个名字,即:\g,对应着命了名的组,named group

第三个参数:string

string,即表示要被处理,要被替换的那个string字符串。

第四个参数:count

对于匹配到的内容,只处理其中一部分。

比如对于:

hello 123 world 456 nihao 789

只是像要处理前面两个数字:123,456,分别给他们加111,而不处理789,

那么就可以写成:

replacedStr = re.sub("(?P\d+)", add111, inputStr, 2);

regex = r"^$\n"
subst = ""
data = re.sub(regex, subst, data, 0, re.MULTILINE)

然后我们再次输出打印,发现空行都已经成功去除了,可是还有一些分割线组成的行。

regex = r"^-+$\n"
subst = ""
data = re.sub(regex, subst, data, 0, re.MULTILINE)

至此,数据清理工作已经完成了。下面我们把文本整理成DataFrame,每一行分别加上行号。

利用换行符把原本完整的文本分割成行。

lines = data.split('\n')

然后给每一行加上行号。

myrows = []
num = 1
for line in lines:myrows.append([num, line])num = num + 1

看看前三行的行号是否已经正常添加。

myrows[:3]
[[1,'[First scene shows the location of Casterly Rock (ancestral seat of House Lannister) on a giant map of Westeros. There are several game pieces representing different House sigils located on different parts of the map.ROBB STARK and CATELYN STARK are at a campsite, within a tent lit up by candles]'],[2, 'CATELYN: Are you sure about this?'],[3, 'ROBB: No.']]

一切正常,下面我们把目前的数组转换成DataFrame

df = pd.DataFrame(myrows)
df.head()
0 1
0 1 [First scene shows the location of Casterly Ro…
1 2 CATELYN: Are you sure about this?
2 3 ROBB: No.
3 4 CATELYN: It’s dangerous.
4 5 [ROBB nods in agreement]

我们给表头重新命名。

df.columns = ['line', 'text']
df.head()
line text
0 1 [First scene shows the location of Casterly Ro…
1 2 CATELYN: Are you sure about this?
2 3 ROBB: No.
3 4 CATELYN: It’s dangerous.
4 5 [ROBB nods in agreement]

后面我们把它转换成为csv格式,以便于R来读取和处理。

df.to_csv('data.csv', index=False)

我们打开data.csv文件,可以看到数据如下:

到此,数据清理和准备工作结束,下面我们用R进行分析。

4. 数据分析

以下操作在RStudio环境下完成
RStudio可以提供一个交互环境,帮我们执行R命令并即时反馈结果

首先设置路径,随后读入处理好的数据,注意设置stringsAsFactors=FALSE,不然R在读取字符串数据的时候,会默认转换为level,后面的分析就做不成了。读取之后,在右侧的数据区域你可以看到script这个变量,双击它,可以看到内容。

setwd("F:/DS/权游情感分析")
script<-read.csv("data.csv", stringsAsFactors=FALSE)

下面我们需要准备分析用的包,执行以下语句安装。

install.packages("dplyr")
install.packages("tidytext")
install.packages("tidyr")
install.packages("textdata")
install.packages("ggplot2")

注意安装新软件包这种操作只需要执行一次。可是我们每次预览结果的时候,文件里所有语句都会被执行一遍。为了避免安装命令被反复执行。当安装结束后,注意删除或者注释掉上面几条语句。

安装了包,使用之前,需要执行library语句调用这些包,或者在packages窗口勾选需要用到的工具包。

library(dplyr)
library(tidytext)
library(tidyr)
library(ggplot2)

万事俱备。下面需要把一句句的文本拆成单词,这样才能和情绪词典里的单词做匹配,从而分析单词的情绪属性。

在R里面,可以采用TidyText方式来做。执行的语句是unnest_token,我们把原先的句子拆分成为单词。

%>%
就是把左件的值发送给右件的表达式,并作为右件表达式函数的第一个参数。

anscombe_tidy <- anscombe %>%mutate(observation = seq_len(n()))

以上代码等价于

anscombe_tidy=mutate(anscombe,observation = seq_len(n()))

%>%来自dplyr包的管道函数,其作用是将前一步的结果直接传参给下一步的函数,从而省略了中间的赋值步骤,可以大量减少内存中的对象,节省内存。

tidy_script <- script %>%unnest_tokens(word, text)
head(tidy_script)
##     line     word
## 1      1    first
## 1.1    1    scene
## 1.2    1    shows
## 1.3    1      the
## 1.4    1 location
## 1.5    1       of

这里原先的行号依然被保留。我们可以看到每一个词来自于哪一行,这有利于下面我们对行甚至段落单位进行分析。调用加拿大国家研究委员会发布的情绪词典。这个词典在tidytext包里面内置了,就叫做nrc

tidy_script %>%inner_join(get_sentiments("nrc")) %>%arrange(line) %>%head(10)

我这里运行时需要下载nrc包,下载速度有点慢,需要耐心等待。

##    line         word    sentiment
## 1     1         rock     positive
## 2     1    ancestral        trust
## 3     1        giant         fear
## 4     1 representing anticipation
## 5     1        stark     negative
## 6     1        stark        trust
## 7     1        stark     negative
## 8     1        stark        trust
## 9     4    dangerous         fear
## 10    4    dangerous     negative

从前10行数据可以看到,有的词对应某一种情绪属性,有的词同时对应多种情绪属性。注意nrc包里面不仅有情绪,而且还有情感(正向和负向)。

这里我们使用index来把原先的行号处理一下,分成段落。%/%代表整除符号,这样0-4行就成为了第一段落,5-9行成为第二段落,以此类推。

mutate函数用来添加列

tidy_script %>%inner_join(get_sentiments("nrc")) %>%count(line, sentiment) %>%mutate(index = line %/% 5) %>%  arrange(index) %>%head(10)
##     line    sentiment     n index
##    <int>        <chr> <int> <dbl>
##  1     1 anticipation     1     0
##  2     1         fear     1     0
##  3     1     negative     2     0
##  4     1     positive     1     0
##  5     1        trust     3     0
##  6     4         fear     1     0
##  7     4     negative     1     0
##  8     5     positive     1     1
##  9     5        trust     1     1
## 10     6     positive     1     1

可以看出,第一段包含的情感很丰富,用可视化的方法,把图绘制出来。绘图采用ggplot包,使用geom_col指令,让R绘制柱状图。对不同的情绪,我们用不同颜色表示出来。

tidy_script %>%inner_join(get_sentiments("nrc")) %>%count(line, sentiment) %>%mutate(index = line %/% 5) %>%ggplot(aes(x=index, y=n, color=sentiment)) %>%+ geom_col()

结果是出来了,可惜看不大清楚。为了区别不同情绪,我们调用facet_wrap函数,把不同情绪拆开,分别绘制。

tidy_script %>%inner_join(get_sentiments("nrc")) %>%count(line, sentiment) %>%mutate(index = line %/% 5) %>%ggplot(aes(x=index, y=n, color=sentiment)) %>%+ geom_col() %>%+ facet_wrap(~sentiment, ncol=3)

分面设置在ggplot2应该也是要经常用到的一项画图内容,在数据对比以及分类显示上有着极为重要的作用,

facet_wrap(facets, nrow = NULL, ncol = NULL, scales = "fixed", shrink = TRUE, as.table = TRUE, drop = TRUE)

facets表示形式为:变量(单元格)

nrow,ncol 分面索要设置成的行和列,参数为数值,表示几行或者几列

scales 参数fixed表示固定坐标轴刻度,free表示反馈坐标轴刻度,也可以单独设置成free_x或free_y

shrink 也和坐标轴刻度有关,如果为TRUE(默认值)则按统计后的数据调整刻度范围,否则按统计前的数据设定坐标。

drop 表示是否去掉没有数据的分组,默认情况下不显示,逻辑值为FALSE

as.table 和小图排列顺序有关的选项。如果为TRUE(默认)则按表格方式排列,即最大值(指分组level值)排在表格最后即右下角,否则排在左上角。

我们做分析时少了一个重要步骤——处理停用词。对于每一个具体场景,我们都需要使用停用词表,把那些可能干扰分析结果的词扔出去。

tidytext提供了默认的停用词表。我们先拿来试试看。这里使用的语句是anti_join,就可以把停用词先去除,再进行情绪词表连接。

我们看看停用词去除后,正向情感词汇的高频词有没有变化。

tidy_script %>%anti_join(stop_words) %>%inner_join(get_sentiments("nrc")) %>%filter(sentiment == "positive") %>%count(word) %>%arrange(desc(n)) %>%head(10)
## # A tibble: 10 x 2
##        word     n
##       <chr> <int>
##  1     lord    13
##  2    guard     9
##  3 daughter     8
##  4 shoulder     7
##  5     love     6
##  6     main     6
##  7    quiet     6
##  8    bride     5
##  9     king     5
## 10    music     5

从结果看出,停用词表里没有包含我们需要去除的名词。于是我们需要自己来修订停用词表。使用R中的bind_rows语句,我们就能在基础的预置停用词表基础上,附加上我们自己的停用词。

custom_stop_words <- bind_rows(stop_words,data_frame(word = c("stark", "mother","don", "father", "daughter", "brother", "rock", "ground", "lord", "guard", "shoulder", "king", "main", "grace", "gate", "horse", "eagle", "servent"),lexicon = c("custom")))

这里加入了一些和情绪无关的名词和关系代词。名词还是保留了一些。例如“新娘”总该是和好的情感和情绪相连吧。用了定制的停用词表后,我们来看看词频的变化。

tidy_script %>%anti_join(custom_stop_words) %>%inner_join(get_sentiments("nrc")) %>%filter(sentiment == "positive") %>%count(word) %>%arrange(desc(n)) %>%head(10)
## # A tibble: 10 x 2
##           word     n
##          <chr> <int>
##  1        love     6
##  2       quiet     6
##  3       bride     5
##  4       music     5
##  5        rest     5
##  6     finally     4
##  7        food     3
##  8     forward     3
##  9        hope     3
## 10 hospitality     3

从结果可以看出,这次积极词汇好多了基本符合情绪分析的需要

做好了基础的修订工作,下面来重新作图吧。我们把停用词表加进去,并且还用filter语句把情感属性删除掉了。因为我们分析的对象是情绪(emotion),而不是情感(sentiment),也就是将积极和消极的情感熟悉去除。

tidy_script %>%anti_join(custom_stop_words) %>%inner_join(get_sentiments("nrc")) %>%filter(sentiment != "negative" & sentiment != "positive") %>%count(line, sentiment) %>%mutate(index = line %/% 5) %>%ggplot(aes(x=index, y=n, color=sentiment)) %>%+ geom_col() %>%+ facet_wrap(~sentiment, ncol=3)

这幅图一下子变得清晰明了,情绪变化层次明显,值得琢磨。

在这一集的结尾,可以看出多种情绪混杂交织——欢快的气氛陡然下降,期待与信任在波动,厌恶在不断上涨,恐惧与悲伤陡然上升,愤怒突破天际,交杂着数次的惊讶……

因为这一集的故事,有个另外的名字,叫做《红色婚礼》。

5. 收获

通过跟着王老师项目的学习,我初步掌握了如下技能:

  1. 如何用Python对特殊的文本做数据清洗,从中找出有价值的信息,并且去掉空行等内容;
  2. 如何用DataFrame对数据进行存储、表示与格式转换,在Python和R中交换数据;
  3. 如何使用RStudio环境,用R 做交互式编程;
  4. 如何利用tidytext方式来处理情感分析与情绪分析;
  5. 如何设置自己的停用词表;
  6. 如何用ggplot绘制多维度切面图形。

在过程中遇到一些难题最后都一一解决了,感谢王老师的干货,欢迎大家共同学习交流!

利用Python和R对权游剧本进行NLP情绪分析相关推荐

  1. 利用python机器学习库进行Kaggle皮马印第安人糖尿病预测分析

    利用python机器学习库进行Kaggle皮马印第安人糖尿病预测分析 项目摘要 本项目主要使用python对各医学参数与糖尿病之间的关系进行可视化分析.描述性分析.使用scikit-learn机器学习 ...

  2. python房价预测_您的选房系统已上线——利用python和R如何进行房价预测

    本文约1500字,阅读需要5分钟.讲述了如何使用python进行房价信息获取,如何利用R构建回归模型以达到预测上海某个地区房价的目的. 关键词:买房 Python 选房 R 定价 本文讲述了借助Pyt ...

  3. python dlib人脸识别_python3+dlib人脸识别及情绪分析

    一.介绍 我想做的是基于人脸识别的表情(情绪)分析.看到网上也是有很多的开源库提供使用,为开发提供了很大的方便.我选择目前用的比较多的dlib库进行人脸识别与特征标定.使用python也缩短了开发周期 ...

  4. python网络爬虫_一篇文章教会你利用Python网络爬虫获取穷游攻略

    点击上方"IT共享之家",进行关注 回复"资料"可获赠Python学习福利 [一.项目背景] 穷游网提供原创实用的出境游旅行指南.攻略,旅行社区和问答交流平台, ...

  5. 10分钟教你利用Python网络爬虫获取穷游攻略

    完整源码在底部 [一.项目背景] 穷游网提供原创实用的出境游旅行指南.攻略,旅行社区和问答交流平台,以及智能的旅行规划解决方案,同时提供签证.保险.机票.酒店预订.租车等在线增值服务.穷游" ...

  6. 一篇文章教会你利用Python网络爬虫获取穷游攻略

    [一.项目背景] 穷游网提供原创实用的出境游旅行指南.攻略,旅行社区和问答交流平台,以及智能的旅行规划解决方案,同时提供签证.保险.机票.酒店预订.租车等在线增值服务.穷游"鼓励和帮助中国旅 ...

  7. 用python写个生日快乐_祝自己生日快乐 | 利用Python和R分析一年写作

    想不清自己有多久没有过生日了,即便是18岁那年的生日,也是上完课照常回去.或许是我的日子过得过于浑浑噩噩,没有什么可以庆祝,或许我认为过生日是过于矫情的一种行为吧. 但是反刻奇也是一种刻奇,没有必要坚 ...

  8. python绘制生日快乐图片_祝自己生日快乐 | 利用Python和R分析一年写作

    想不清自己有多久没有过生日了,即便是18岁那年的生日,也是上完课照常回去.或许是我的日子过得过于浑浑噩噩,没有什么可以庆祝,或许我认为过生日是过于矫情的一种行为吧. 但是反刻奇也是一种刻奇,没有必要坚 ...

  9. 利用python爬取京东平台评论及图片并进行分析

    一.背景及目的 在淘宝.京东等网络平台上购物,逐渐成为大众化的购物方式.但假冒伪劣产品在这个摸不着实物的购物平台严重危害着消费者的购物体验,即使我们可以通过七天无理由退货退款来维护我们的合法权益,但是 ...

最新文章

  1. xa 全局锁_分布式事务如何实现?深入解读 Seata 的 XA 模式
  2. 实习小白::(转) Cocos2d-x 3.0开发(十三)使用CocoStudio编辑帧事件并关联到程序...
  3. racte margin 居中 失效_上干货,微信用情侣签名她肯定很开心,微信个性签名居中隐藏技巧...
  4. linux6.8安装图形桌面,图形/文本界面安装CentOS 6.8系统详解
  5. MyBatis 二级缓存
  6. 不同修饰符的访问权限(private,缺省(默认即default),protected,public)
  7. ROS 图像相关的命令与应用
  8. 基于QT实现简单的音乐播放器
  9. 原生JavaScript实现幻灯片效果
  10. bootstrap datetimepicker 日期插件
  11. FastDFS详细安装步骤,测试;Nginx中配置FastDFS,并提供优化,下载方法,楼主已测
  12. 黑苹果简单驱动 MultiBeast用法基础篇
  13. 一、rsync +cwrsync实现windows和linux的文件同步
  14. 语法练习——动名词专项训练
  15. java xmladapte_三步解决JAXB生成XML包含CDATA问题—JAVA编程
  16. Adb shell命令直接打开语言设置界面
  17. 建立区域经济大脑,驱动产业创新发展
  18. mysql table plugin,MySql报错Table mysql.plugin doesn’t exist的解决方法
  19. 华为OD机试题 - 找出重复代码(JavaScript)| 包含代码编写思路
  20. 扬帆际海——怎么做跨境电商?

热门文章

  1. Django Web 开发极简实战
  2. Android音频处理知识(一)MediaRecorder录制音频
  3. GreenPlum常用字符串函数
  4. Logistic-tent混沌系统matlab
  5. P5.js 实现交互式动态绘画
  6. Python爬虫:用最普通的方法爬取ts文件并合成为mp4格式
  7. 论文笔记-2019-ImageNet-trained CNNs are biased towards texture; increasing shape bias improves accuracy
  8. 深入理解地址翻译 CSAPP
  9. CD-Hit 生信 碱基序列去除冗余的方法
  10. WLAN旁挂组网二层直连