小言_互联网的博客

用Python对哈利波特系列小说进行情感分析

337人阅读  评论(0)

Python&Stata数据采集与数据分析实证前沿寒假工作坊  现在开始招生了,有兴趣的同学和老师可以戳进来了解

准备数据

现有的数据是一部小说放在一个txt里,我们想按照章节(列表中第一个就是章节1的内容,列表中第二个是章节2的内容)进行分析,这就需要用到正则表达式整理数据。

比如我们先看看 01-Harry Potter and the Sorcerer's Stone.txt" 里的章节情况,我们打开txt

经过检索发现,所有章节存在规律性表达

[Chapter][空格][整数][换行符\n][可能含有空格的英文标题][换行符\n]

我们先熟悉下正则,使用这个设计一个模板pattern提取章节信息


   
  1. import re
  2. import nltk
  3. raw_text = open( "data/01-Harry Potter and the Sorcerer's Stone.txt").read()
  4. pattern = 'Chapter \d+\n[a-zA-Z ]+\n'
  5. re.findall(pattern, raw_text)

   
  1. [ 'Chapter 1\nThe Boy Who Lived\n',
  2. 'Chapter 2\nThe Vanishing Glass\n',
  3. 'Chapter 3\nThe Letters From No One\n',
  4. 'Chapter 4\nThe Keeper Of The Keys\n',
  5. 'Chapter 5\nDiagon Alley\n',
  6. 'Chapter 7\nThe Sorting Hat\n',
  7. 'Chapter 8\nThe Potions Master\n',
  8. 'Chapter 9\nThe Midnight Duel\n',
  9. 'Chapter 10\nHalloween\n',
  10. 'Chapter 11\nQuidditch\n',
  11. 'Chapter 12\nThe Mirror Of Erised\n',
  12. 'Chapter 13\nNicholas Flamel\n',
  13. 'Chapter 14\nNorbert the Norwegian Ridgeback\n',
  14. 'Chapter 15\nThe Forbidden Forest\n',
  15. 'Chapter 16\nThrough the Trapdoor\n',
  16. 'Chapter 17\nThe Man With Two Faces\n']

熟悉上面的正则表达式操作,我们想更精准一些。我准备了一个test文本,与实际小说中章节目录表达相似,只不过文本更短,更利于理解。按照我们的预期,我们数据中只有5个章节,那么列表的长度应该是5。这样操作后的列表中第一个内容就是章节1的内容,列表中第二个内容是章节2的内容。


   
  1. import re
  2. test = "" "Chapter 1\nThe Boy Who Lived\nMr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much. They were the last people you’d expect to be involved in anything strange or mysterious, because they just didn’t hold with such nonsense.\nMr. Dursley was the director of a firm called Grunnings,
  3. Chapter 2\nThe Vanishing Glass\nFor a second, Mr. Dursley didn’t realize what he had seen — then he jerked his head around to look again. There was a tabby cat standing on the corner of Privet Drive, but there wasn’t a map in sight. What could he have been thinking of? It must have been a trick of the light. Mr. Dursley blinked and stared at the cat.
  4. Chapter 3\nThe Letters From No One\nThe traffic moved on and a few minutes later, Mr. Dursley arrived in the Grunnings parking lot, his mind back on drills.\nMr. Dursley always sat with his back to the window in his office on the ninth floor. If he hadn’t, he might have found it harder to concentrate on drills that morning.
  5. Chapter 4\nThe Keeper Of The Keys\nHe didn’t know why, but they made him uneasy. This bunch were whispering excitedly, too, and he couldn’t see a single collecting tin.
  6. Chapter 5\nDiagon Alley\nIt was a few seconds before Mr. Dursley realized that the man was wearing a violet cloak. " ""
  7. #获取章节内容列表(列表中第一个内容就是章节 1的内容,列表中第二个内容是章节 2的内容)
  8. #为防止列表中有空内容,这里加了一个条件判断,保证列表长度与章节数预期一致
  9. chapter_contents = [c for c in re.split( 'Chapter \d+\n[a-zA-Z ]+\n', test) if c]
  10. chapter_contents

   
  1. [ 'Mr. and Mrs. Dursley, of number four, Privet Drive, were proud to say that they were perfectly normal, thank you very much. They were the last people you’d expect to be involved in anything strange or mysterious, because they just didn’t hold with such nonsense.\nMr. Dursley was the director of a firm called Grunnings,\n ',
  2. 'For a second, Mr. Dursley didn’t realize what he had seen — then he jerked his head around to look again. There was a tabby cat standing on the corner of Privet Drive, but there wasn’t a map in sight. What could he have been thinking of? It must have been a trick of the light. Mr. Dursley blinked and stared at the cat.\n ',
  3. 'The traffic moved on and a few minutes later, Mr. Dursley arrived in the Grunnings parking lot, his mind back on drills.\nMr. Dursley always sat with his back to the window in his office on the ninth floor. If he hadn’t, he might have found it harder to concentrate on drills that morning.\n ',
  4. 'He didn’t know why, but they made him uneasy. This bunch were whispering excitedly, too, and he couldn’t see a single collecting tin. \n ',
  5. 'It was a few seconds before Mr. Dursley realized that the man was wearing a violet cloak. ']

能得到哈利波特的章节内容列表

也就意味着我们可以做真正的文本分析了

数据分析

章节数对比


   
  1. import os
  2. import re
  3. import matplotlib.pyplot as plt
  4. colors = [ '#78C850', '#A8A878', '#F08030', '#C03028', '#6890F0', '#A890F0', '#A040A0']
  5. harry_potters = [ "Harry Potter and the Sorcerer's Stone.txt",
  6. "Harry Potter and the Chamber of Secrets.txt",
  7. "Harry Potter and the Prisoner of Azkaban.txt",
  8. "Harry Potter and the Goblet of Fire.txt",
  9. "Harry Potter and the Order of the Phoenix.txt",
  10. "Harry Potter and the Half-Blood Prince.txt",
  11. "Harry Potter and the Deathly Hallows.txt"]
  12. #横坐标为小说名
  13. harry_potter_names = [n.replace( 'Harry Potter and the ', '')[:-4]
  14. for n in harry_potters]
  15. #纵坐标为章节数
  16. chapter_nums = []
  17. for harry_potter in harry_potters:
  18. file = "data/"+harry_potter
  19. raw_text = open(file).read()
  20. pattern = 'Chapter \d+\n[a-zA-Z ]+\n '
  21. chapter_contents = [c for c in re.split(pattern, raw_text) if c]
  22. chapter_nums.append(len(chapter_contents))
  23. #设置画布尺寸
  24. plt.figure(figsize=(20, 10))
  25. #图的名字,字体大小,粗体
  26. plt.title('Chapter Number of Harry Potter ', fontsize=25, weight='bold ')
  27. #绘制带色条形图
  28. plt.bar(harry_potter_names, chapter_nums, color=colors)
  29. #横坐标刻度上的字体大小及倾斜角度
  30. plt.xticks(rotation=25, fontsize=16, weight='bold ')
  31. plt.yticks(fontsize=16, weight='bold ')
  32. #坐标轴名字
  33. plt.xlabel('Harry Potter Series ', fontsize=20, weight='bold ')
  34. plt.ylabel('Chapter Number ', rotation=25, fontsize=20, weight='bold ')
  35. plt.show()

从上面可以看出哈利波特系列小说的后四部章节数据较多(这分析没啥大用处,主要是练习)

用词丰富程度

如果说一句100个词的句子,同时词语不带重样的,那么用词的丰富程度为100。

而如果说同样长度的句子,只用到20个词语,那么用词的丰富程度为100/20=5。


   
  1. import os
  2. import re
  3. import matplotlib.pyplot as plt
  4. from nltk import word_tokenize
  5. from nltk.stem.snowball importSnowballStemmer
  6. plt.style.use( 'fivethirtyeight')
  7. colors = [ '#78C850', '#A8A878', '#F08030', '#C03028', '#6890F0', '#A890F0', '#A040A0']
  8. harry_potters = [ "Harry Potter and the Sorcerer's Stone.txt",
  9. "Harry Potter and the Chamber of Secrets.txt",
  10. "Harry Potter and the Prisoner of Azkaban.txt",
  11. "Harry Potter and the Goblet of Fire.txt",
  12. "Harry Potter and the Order of the Phoenix.txt",
  13. "Harry Potter and the Half-Blood Prince.txt",
  14. "Harry Potter and the Deathly Hallows.txt"]
  15. #横坐标为小说名
  16. harry_potter_names = [n.replace( 'Harry Potter and the ', '')[:-4]
  17. for n in harry_potters]
  18. #用词丰富程度
  19. richness_of_words = []
  20. stemmer = SnowballStemmer("english")
  21. for harry_potter in harry_potters:
  22. file = "data/"+harry_potter
  23. raw_text = open(file).read()
  24. words = word_tokenize(raw_text)
  25. words = [stemmer.stem(w.lower()) for w in words]
  26. wordset = set(words)
  27. richness = len(words)/len(wordset)
  28. richness_of_words.append(richness)
  29. #设置画布尺寸
  30. plt.figure(figsize=(20, 10))
  31. #图的名字,字体大小,粗体
  32. plt.title('The Richness of Word in Harry Potter ', fontsize=25, weight='bold ')
  33. #绘制带色条形图
  34. plt.bar(harry_potter_names, richness_of_words, color=colors)
  35. #横坐标刻度上的字体大小及倾斜角度
  36. plt.xticks(rotation=25, fontsize=16, weight='bold ')
  37. plt.yticks(fontsize=16, weight='bold ')
  38. #坐标轴名字
  39. plt.xlabel('Harry Potter Series ', fontsize=20, weight='bold ')
  40. plt.ylabel('Richness of Words ', rotation=25, fontsize=20, weight='bold ')
  41. plt.show()

情感分析

哈利波特系列小说情绪发展趋势,这里使用VADER,有现成的库vaderSentiment,这里使用其中的polarity_scores函数,可以得到

  • neg:负面得分

  • neu:中性得分

  • pos:积极得分

  • compound: 综合情感得分


   
  1. from vaderSentiment.vaderSentiment importSentimentIntensityAnalyzer
  2. analyzer = SentimentIntensityAnalyzer()
  3. test = 'i am so sorry'
  4. analyzer.polarity_scores(test)
{'neg': 0.443, 'neu': 0.557, 'pos': 0.0, 'compound': -0.1513}

   
  1. import os
  2. import re
  3. import matplotlib.pyplot as plt
  4. from nltk.tokenize import sent_tokenize
  5. from vaderSentiment.vaderSentiment importSentimentIntensityAnalyzer
  6. harry_potters = [ "Harry Potter and the Sorcerer's Stone.txt",
  7. "Harry Potter and the Chamber of Secrets.txt",
  8. "Harry Potter and the Prisoner of Azkaban.txt",
  9. "Harry Potter and the Goblet of Fire.txt",
  10. "Harry Potter and the Order of the Phoenix.txt",
  11. "Harry Potter and the Half-Blood Prince.txt",
  12. "Harry Potter and the Deathly Hallows.txt"]
  13. #横坐标为章节序列
  14. chapter_indexes = []
  15. #纵坐标为章节情绪得分
  16. compounds = []
  17. analyzer = SentimentIntensityAnalyzer()
  18. chapter_index = 1
  19. for harry_potter in harry_potters:
  20. file = "data/"+harry_potter
  21. raw_text = open(file).read()
  22. pattern = 'Chapter \d+\n[a-zA-Z ]+\n'
  23. chapters = [c for c in re.split(pattern, raw_text) if c]
  24. #计算每个章节的情感得分
  25. for chapter in chapters:
  26. compound = 0
  27. sentences = sent_tokenize(chapter)
  28. for sentence in sentences:
  29. score = analyzer.polarity_scores(sentence)
  30. compound += score[ 'compound']
  31. compounds. append(compound/ len(sentences))
  32. chapter_indexes. append(chapter_index)
  33. chapter_index+= 1
  34. #设置画布尺寸
  35. plt.figure(figsize=( 20, 10))
  36. #图的名字,字体大小,粗体
  37. plt.title( 'Average Sentiment of the Harry Potter', fontsize= 25, weight= 'bold')
  38. #绘制折线图
  39. plt.plot(chapter_indexes, compounds, color= '#A040A0')
  40. #横坐标刻度上的字体大小及倾斜角度
  41. plt.xticks(rotation= 25, fontsize= 16, weight= 'bold')
  42. plt.yticks(fontsize= 16, weight= 'bold')
  43. #坐标轴名字
  44. plt.xlabel( 'Chapter', fontsize= 20, weight= 'bold')
  45. plt.ylabel( 'Average Sentiment', rotation= 25, fontsize= 20, weight= 'bold')
  46. plt.show()

曲线不够平滑,为了熨平曲线波动,自定义了一个函数


   
  1. import numpy as np
  2. import os
  3. import re
  4. import matplotlib.pyplot as plt
  5. from nltk.tokenize import sent_tokenize
  6. from vaderSentiment.vaderSentiment importSentimentIntensityAnalyzer
  7. #曲线平滑函数
  8. def movingaverage(value_series, window_size):
  9. window = np.ones( int(window_size))/float(window_size)
  10. return np.convolve(value_series, window, 'same')
  11. harry_potters = [ "Harry Potter and the Sorcerer's Stone.txt",
  12. "Harry Potter and the Chamber of Secrets.txt",
  13. "Harry Potter and the Prisoner of Azkaban.txt",
  14. "Harry Potter and the Goblet of Fire.txt",
  15. "Harry Potter and the Order of the Phoenix.txt",
  16. "Harry Potter and the Half-Blood Prince.txt",
  17. "Harry Potter and the Deathly Hallows.txt"]
  18. #横坐标为章节序列
  19. chapter_indexes = []
  20. #纵坐标为章节情绪得分
  21. compounds = []
  22. analyzer = SentimentIntensityAnalyzer()
  23. chapter_index = 1
  24. for harry_potter in harry_potters:
  25. file = "data/"+harry_potter
  26. raw_text = open(file).read()
  27. pattern = 'Chapter \d+\n[a-zA-Z ]+\n'
  28. chapters = [c for c in re.split(pattern, raw_text) if c]
  29. #计算每个章节的情感得分
  30. for chapter in chapters:
  31. compound = 0
  32. sentences = sent_tokenize(chapter)
  33. for sentence in sentences:
  34. score = analyzer.polarity_scores(sentence)
  35. compound += score[ 'compound']
  36. compounds. append(compound/ len(sentences))
  37. chapter_indexes. append(chapter_index)
  38. chapter_index+= 1
  39. #设置画布尺寸
  40. plt.figure(figsize=( 20, 10))
  41. #图的名字,字体大小,粗体
  42. plt.title( 'Average Sentiment of the Harry Potter',
  43. fontsize= 25,
  44. weight= 'bold')
  45. #绘制折线图
  46. plt.plot(chapter_indexes, compounds,
  47. color= 'red')
  48. plt.plot(movingaverage(compounds, 10),
  49. color= 'black',
  50. linestyle= ':')
  51. #横坐标刻度上的字体大小及倾斜角度
  52. plt.xticks(rotation= 25,
  53. fontsize= 16,
  54. weight= 'bold')
  55. plt.yticks(fontsize= 16,
  56. weight= 'bold')
  57. #坐标轴名字
  58. plt.xlabel( 'Chapter',
  59. fontsize= 20,
  60. weight= 'bold')
  61. plt.ylabel( 'Average Sentiment',
  62. rotation= 25,
  63. fontsize= 20,
  64. weight= 'bold')
  65. plt.show()

近期文章

精选课程 | Python文本数据分析实战(学术)

Python爬虫与Stata应用能力提升与实证前沿  寒假工作坊

NRC词语情绪词典和词语色彩词典

Loughran&McDonald金融文本情感分析库

股评师分析报告文本情感分析预测股价

使用分析师报告中含有的情感信息预测上市公司股价变动

【公开视频课】Python语法快速入门

【公开视频课】Python爬虫快速入门

一行pandas代码生成哑变量

使用Python读取图片中的文本数据

代码不到40行的超燃动态排序图

情绪及色彩词典获取方式,请在公众号后台回复关键词“20191217” ,

如果想做文本分析

可购买网课 | Python文本数据分析实战(学术) 

或参加Python&Stata数据采集与数据分析实证前沿寒假工作坊  


转载:https://blog.csdn.net/weixin_38008864/article/details/103590609
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场