数据分析案例-文本挖掘与中文文本的统计分析

 

🤵‍♂️ 个人主页:@艾派森的个人主页

✍🏻作者简介:Python学习者
🐋 希望大家多多支持,我们一起进步!😄
如果文章对你有帮助的话,
欢迎评论 💬点赞👍🏻 收藏 📂加关注+


目录

项目背景介绍 

数据准备

项目流程

1.读取小说内容

2.统计词频

3.去除停用词

4.绘制词云图

5.章回处理


项目背景介绍 

        四大名著,又称四大小说,是汉语文学中不可多得的作品。这四部著作历久不衰,其中的故事、场景,已经深深地影响了国人的思想观念、价值取向。四部著作都有很高的艺术水平,细致的刻画和所蕴含的思想都为历代读者所称道。

        本次将以小说HLM为例,介绍中文文本的统计分析和文本发掘等方面的基本知识。

 数据准备

关于小说内容,读者可自行搜集。

项目流程

1.读取小说内容

# 获取HLM文本数据
with open('HLM.txt','r',encoding='utf-8')as f:
    text = f.read()

2.统计词频

import jieba

# 分词并统计词频
def wordFreq(text,topn):
    words = jieba.lcut(text.strip()) # 对文本进行分词操作
    counts = {}
    for word in words:  # 统计每个词出现的频率,存放在字典counts中
        if len(word) == 1:  # 如果该词的长度为1,则跳过,不参与统计。
            continue
        counts[word] = counts.get(word,0) + 1
    items = list(counts.items())
    items.sort(key=lambda x:x[1],reverse=True)  # 按照词频进行排序
    f = open('HLM_词频.txt','w',encoding='utf-8')
    for i in range(topn):  # topn表示要取的词的个数,将频率最高的topn个词及其频率数存放在文件中
        word,count = items[i]
        f.writelines("{}\t{}\n".format(word,count))
    f.close() 

wordFreq(text,20)  # 这里我们提取出频率最高的前20个词

 出现频率最高的词语是“宝玉”,出现了3772次,宝玉当仁不让的是《HLM》的一号主角。后面紧跟的高频词是“什么”,“一个”,这些也都是无意义的词语,需要我们进一步去除。

3.去除停用词

这里我们只需要加载停用词库,统计词频的时候加上判断即可。

# 分词并统计词频
def wordFreq(text,topn):
    words = jieba.lcut(text.strip()) # 对文本进行分词操作
    # 加载停用词库
    stopwords = [line.strip() for line in open('停用词库.txt','r',encoding='utf-8').readlines()]
    counts = {}
    for word in words:  # 统计每个词出现的频率,存放在字典counts中
        if len(word) == 1:  # 如果该词的长度为1,则跳过,不参与统计。
            continue
        elif word not in stopwords:  # 如果该词不在停用词列表stopwords中,才参与统计
            counts[word] = counts.get(word,0) + 1
    items = list(counts.items())
    items.sort(key=lambda x:x[1],reverse=True)  # 按照词频进行排序
    f = open('HLM_词频.txt','w',encoding='utf-8')
    for i in range(topn):  # topn表示要取的词的个数,将频率最高的topn个词及其频率数存放在文件中
        word,count = items[i]
        f.writelines("{}\t{}\n".format(word,count))
    f.close() 

 

 观察输出结果,不难发现“凤姐”和“凤姐儿”应该是一个人物,包括后面的“黛玉”和“林黛玉”,“林妹妹”也是一个人,“宝玉”以及“宝二爷”也应该一起统计

所以我们还需要处理小说中同一人物,不同称呼的情况。对上面的代码进行改进。

# 分词并统计词频
def wordFreq(text,topn):
    words = jieba.lcut(text.strip()) # 对文本进行分词操作
    # 加载停用词库
    stopwords = [line.strip() for line in open('停用词库.txt','r',encoding='utf-8').readlines()]
    counts = {}
    for word in words:  # 统计每个词出现的频率,存放在字典counts中
        if len(word) == 1:  # 如果该词的长度为1,则跳过,不参与统计。
            continue
        elif word not in stopwords:  # 如果该词不在停用词列表stopwords中,才参与统计
            if word == '凤姐儿':
                word = '凤姐'
            elif word == '林黛玉' or word == '林妹妹':
                word = '黛玉'
            elif word == '二爷':
                word = '宝玉'
            counts[word] = counts.get(word,0) + 1
    items = list(counts.items())
    items.sort(key=lambda x:x[1],reverse=True)  # 按照词频进行排序
    f = open('HLM_词频.txt','w',encoding='utf-8')
    for i in range(topn):  # topn表示要取的词的个数,将频率最高的topn个词及其频率数存放在文件中
        word,count = items[i]
        f.writelines("{}\t{}\n".format(word,count))
    f.close() 

4.绘制词云图

 这里我们调用获取词频函数,获取TOP500,最后绘制词云图

# 绘制词云
import matplotlib.pyplot as plt
import wordcloud
import imageio
wordFreq(text,500)  # 获取TOP500的词频
word_cloud_text = open('HLM_词频.txt','r',encoding='utf-8').read()
bg_pic = imageio.imread('star.jpg') # 读入形状图片
wc = wordcloud.WordCloud(font_path=r'C:\Windows\Fonts\simhei.ttf',
                            background_color='white',
                            width=1000,
                            max_words=200,
                            mask=bg_pic,  # mask参数设置词云形状
                            height=860,
                            margin=2
                            ).generate(word_cloud_text)
wc.to_file('HLMcloud_star.png')  # 保存图片

5.章回处理

导入Python中的正则表达式(re模块)通过正则匹配,找到文中所有“第**回”形式的字符。“\u4e00”和“\u9fa5”是unicode编码,并且正好是中文编码的开始和结束的两个值,所以这个正则表达式可以用来判断字符串中是否包含中文。

# 章回处理
import re
chapter = re.findall('第[\u4e00-\u9fa5]+回',text)
lst_chapter = []
for x in chapter:  # 去除重复的章节
    if x not in lst_chapter and len(x)<=5:
        lst_chapter.append(x)
print(lst_chapter)

 获取每一回起始和结束数据

lst_start_chapterIndex = []
for x in lst_chapter:  # 找出每一回在原文中的起始位置
    lst_start_chapterIndex.append(text.index(x))

lst_end_chapterIndex = lst_start_chapterIndex[1:]+[len(text)]  # 找出每一回在原文中的结束位置,本回的结束位置就是下一回的起始位置。最后一回的结束位置就是全文的结束。zip将每一回的起始和结束位置拼成一个元组,存放在lst_chapterindex列表中。
lst_chapterIndex = list(zip(lst_start_chapterIndex,lst_end_chapterIndex))
print(lst_chapterIndex)

5.1HLM之“刘姥姥三进荣国府” 

统计在每一回中刘姥姥的出场次数并用折线图可视化。

# 统计刘姥姥出现的次数
cnt_liulaolao = []
for i in range(120):
    start = lst_chapterIndex[i][0]
    end = lst_chapterIndex[i][1]
    cnt_liulaolao.append(text[start:end].count('刘姥姥'))
plt.rcParams['font.sans-serif'] = ['SimHei'] #解决中文显示
plt.rcParams['axes.unicode_minus'] = False   #解决符号无法显示
plt.figure(figsize=(15,6))
plt.plot(range(120),cnt_liulaolao,label='刘姥姥出场次数')
plt.title('《HLM》——刘姥姥三进荣国府',fontdict={'fontsize':14})
plt.xlabel('章节数',fontdict={'fontsize':14})
plt.ylabel('出现次数',fontdict={'fontsize':14})
plt.legend()
plt.show()

5.2HLM之“哭说笑闹总关情”  

        我们尝试分析一下在小说的每一回里,“笑”和“喜”,“哭”与“悲”分别出现的次数,能不能通过这样一个小小的切入点,看一看贾府的兴衰与荣辱变化。统计每一回中“笑”和“喜”,“哭”与“悲”的出现次数。 并用折线图可视化。

# 统计情绪次数
cnt_laugh = []
cnt_cry = []
for i in range(120):
    start = lst_chapterIndex[i][0]
    end = lst_chapterIndex[i][1]
    cnt_laugh.append(text[start:end].count('笑')+text[start:end].count('喜'))
    cnt_cry.append(text[start:end].count('哭')+text[start:end].count('悲'))
# 可视化
plt.figure(figsize=(15,6))
plt.plot(range(120),cnt_laugh,label='笑和喜')
plt.plot(range(120),cnt_cry,label='哭和悲')
plt.title('《HLM》120回悲喜变化图',fontdict={'fontsize':14})
plt.xlabel('章节数',fontdict={'fontsize':14})
plt.ylabel('出现次数',fontdict={'fontsize':14})
plt.legend()
plt.show()

 5.3HLM之平均段落数与字数

统计每一章段落数和字数并可视化。

cnt_chap = []  # 存放每一回的段落数
cnt_word = []  # 存放每一回的字符总数
for i in range(120):
    start = lst_chapterIndex[i][0]
    end = lst_chapterIndex[i][1]
    cnt_chap.append(text[start:end].count('\n'))
    cnt_word.append(len(text[start:end]))

# 可视化
plt.figure(figsize=(15,8))
plt.scatter(cnt_chap,cnt_word)
for i in range(120):
    plt.text(cnt_chap[i]-2,cnt_word[i]+100,lst_chapter[i],size=7)
plt.xlabel('章节段数',fontdict={'fontsize':14})
plt.ylabel('章节字数',fontdict={'fontsize':14})
plt.title('《HLM》120回',fontdict={'fontsize':14})
plt.show()

 5.4HLM之人物社交关系网络

提取小说中的人名

分析人物关系,首先我们需要将书中涉及到的人物姓名提取出来。我们利用在之前生成的词频文件,抽取排名靠前的二十四个人物,研究他们之间的社交关系情况。简便起见,将这些人物名称存放在列表Names中。 

Names=['宝玉','凤姐','贾母','黛玉','王夫人','老太太','袭人','贾琏','平儿','宝钗','薛姨妈','探春','鸳鸯','贾政','晴雯','湘云','刘姥姥','邢夫人','贾珍','紫鹃','香菱','尤氏','薛蟠','贾赦']

基于共现关系获取人物关系权重

一般我们认为,在一篇文章中的同一段出现的两个人物之间,一定具有某种关联,因此我们将每一段中的人物角色抽取出来,然后以段落为单位,统计两个角色同时出现的共现次数,并把结果存在一个二维矩阵之中。

Names=['宝玉','凤姐','贾母','黛玉','王夫人','老太太','袭人','贾琏','平儿','宝钗','薛姨妈','探春','鸳鸯','贾政','晴雯','湘云','刘姥姥','邢夫人','贾珍','紫鹃','香菱','尤氏','薛蟠','贾赦']
relations = {}
lst_para = text.split('\n')  # 按段落划分,假设在同一段落中出现的人物具有共现关系
for t in lst_para:
    for name1 in Names:
        if name1 in t:
            for name2 in Names:
                if name2 in t and name1 != name2 and (name2,name1) not in relations:
                    relations[(name1,name2)] = relations.get((name1,name2),0)+1
print(relations.items())

接下来对权重值做归一化操作,找到共现次数的最大值,然后将所有的共现次数映射到0-1之间。

maxRela = max([v for k,v in relations.items()])
relations = {k:v/maxRela for k,v in relations.items()}
print(relations)

 绘制人物社交网络图

使用networkx库,绘制人物社交网络图。

import networkx as nx
plt.figure(figsize=(12,12))
G= nx.Graph()
# 根据relations的数据向G中添加边
for k,v in relations.items():
    G.add_edge(k[0],k[1],weight=v)
elarge = [(u,v)for (u,v,d) in G.edges(data=True) if d['weight']>0.6]
emidle = [(u,v)for (u,v,d) in G.edges(data=True) if (d['weight']>0.3)&(d['weight']<=0.6)]
esmall = [(u,v)for (u,v,d) in G.edges(data=True) if d['weight']<=0.3]
# 设置图形布局
pos = nx.spring_layout(G)
# 设置节点样式
nx.draw_networkx_nodes(G,pos,alpha=0.8,node_size=800)
nx.draw_networkx_edges(G,pos,edgelist=elarge,width=2.5,alpha=0.9,edge_color='g')
nx.draw_networkx_edges(G,pos,edgelist=emidle,width=1.5,alpha=0.6,edge_color='r')
nx.draw_networkx_edges(G,pos,edgelist=esmall,width=1,alpha=0.4,edge_color='b',style='dashed')
nx.draw_networkx_labels(G,pos,font_size=12)
plt.axis('off')
plt.title('《HLM》主要人物社交关系网络图')
plt.show()

 emmm,这个风格好像有点不太好看,我们换个风格。

plt.figure(figsize=(8,6))
pos = nx.circular_layout(G)
# 设置节点样式
nx.draw_networkx_nodes(G,pos,alpha=0.6,node_size=800)
nx.draw_networkx_edges(G,pos,edgelist=elarge,width=2.5,alpha=0.9,edge_color='g')
nx.draw_networkx_edges(G,pos,edgelist=emidle,width=1.5,alpha=0.6,edge_color='r')
nx.draw_networkx_edges(G,pos,edgelist=esmall,width=1,alpha=0.2,edge_color='b',style='dashed')
nx.draw_networkx_labels(G,pos,font_size=12)
plt.axis('off')
plt.title('《HLM》主要人物社交关系网络图')
plt.show()

绿色权值最大,代表关系越深;红色权值处于中间,关系一般;蓝色权值最低,关系较弱。 

 从关系图中,我们可以看出贾宝玉社交关系又多又深,不愧是小说中的主角,社交广泛。

好了,以上就是本次分享的项目案例,如果对读者有所帮助,那就留下你的三连吧。

  • 37
    点赞
  • 208
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

艾派森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值