[Pyhon疫情大数据分析] 三.新闻信息抓取及词云可视化、文本聚类和LDA主题模型文本挖掘

思来想去,虽然很忙,但还是挤时间针对这次肺炎疫情写个Python大数据分析系列博客,包括网络爬虫、可视化分析、GIS地图显示、情感分析、舆情分析、主题挖掘、威胁情报溯源、知识图谱、预测预警及AI和NLP应用等。希望该系列线上远程教学对您有所帮助,也希望早点战胜病毒,武汉加油、湖北加油、全国加油。待到疫情结束樱花盛开,这座英雄的城市等你们来。

首先说声抱歉,最近一直忙着学习安全知识,其他系列文章更新较慢,已经有一些人催更了,哈哈。言归正传,前文分享了腾讯疫情实时数据抓取,结合PyEcharts绘制地图、折线图、柱状图。这篇文章将爬取疫情相关的新闻数据,接着进行中文分词处理及文本聚类、LDA主题模型分析。希望这篇可视化分析文章对您有所帮助,也非常感谢参考文献中老师的分享,一起加油,战胜疫情!如果您有想学习的知识或建议,可以给作者留言~

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

代码下载地址:https://github.com/eastmountyxz/Wuhan-data-analysis

同时推荐前面作者另外五个Python系列文章。从2014年开始,作者主要写了三个Python系列文章,分别是基础知识、网络爬虫和数据分析。2018年陆续增加了Python图像识别和Python人工智能专栏。

在这里插入图片描述

前文阅读:
[Pyhon疫情大数据分析] 一.腾讯实时数据爬取、Matplotlib和Seaborn可视化分析全国各地区、某省各城市、新增趋势
[Pyhon疫情大数据分析] 二.PyEcharts绘制全国各地区、某省各城市疫情地图及可视化分析



一.数据抓取

本次爬虫目标网站是中国社会组织公共服务平台,读者可以针对不同的网站进行抓取。

第一步 分析网站
通过浏览器“审查元素”查看源代码并获取新闻的标题、URL、时间等。不同网站有不同分析方法,本文重点是文本挖掘,数据抓取仅提供一些思路。

在这里插入图片描述

第二步,进入具体的新闻页面抓取相关的文本信息。

  • article_title = text_html.xpath(’//*[@id=“fontinfo”]/p[2]/b[1]//text()’)
  • publish_time = text_html.xpath(’/html/body/div[2]/div/ul[1]/li[3]/strong/text()’)[0][5:]
  • source_text = text_html.xpath(’//*[@id=“fontinfo”]/p[last()]//text()’)[0]
  • text_list = text_html.xpath(’//*[@id=“fontinfo”]//text()’)

在这里插入图片描述

在这里插入图片描述

第三步,本爬虫存在一个技巧,每条新闻的URL非常相似,这里仅变换参数来抓取新闻。

  • 最初一篇新闻(2020-03-06)URL:http://www.chinanpo.gov.cn/1944/125177/nextindex.html
  • 最后一篇新闻(2020-01-26)URL:http://www.chinanpo.gov.cn/1944/123496/nextindex.html

我们只需要每次抓取数据时,通过“下一页”定位下次需要抓取的URL即可,核心代码为:

  • next_url = “http://www.chinanpo.gov.cn” + text_html.xpath(’/html/body/div[2]/div/ul[1]/li[2]/a[2]/@href’)[0]

在这里插入图片描述

第四步,数据抓取完整代码如下所示,建议读者直接下载我的文本进行数据分析,而不用再去爬取数据高访问对方数据库。

import requests,re, csv, sys, time
from lxml import html
from fake_useragent import UserAgent

# 记录起始时间
startTime = time.time()

# 创建CSV文件,并写入表头信息
fp = open('中国社会组织_疫情防控.csv','a',newline='',encoding='utf-8-sig')
writer = csv.writer(fp)
writer.writerow(("标题", "时间", "URL", "正文内容", "来源"))

#----------------------------------------------抓取数据----------------------------------------------
def spider_html_info(url):
    try:
        headers = {
            "User-Agent" : UserAgent().chrome #chrome浏览器随机代理
        }
        response = requests.get(url=url, headers=headers).text
        text_html = html.fromstring(response)
        
        # 获取下一页链接,先其他元素获取一页链接,保证程序的强壮性
        next_url = "http://www.chinanpo.gov.cn" + text_html.xpath('/html/body/div[2]/div/ul[1]/li[2]/a[2]/@href')[0]
        print("next_url", next_url)
    
        # 获取文章标题
        article_title = text_html.xpath('//*[@id="fontinfo"]/p[2]/b[1]//text()')
        title = "".join(article_title)
        if title == "":
            title = "".join(text_html.xpath('//*[@id="fontinfo"]/p[3]/b[1]//text()'))
        print ("title = ",title)
        
        # 获取发布时间
        publish_time = text_html.xpath('/html/body/div[2]/div/ul[1]/li[3]/strong/text()')[0][5:]
        print ("publish_time = ", publish_time)
        print ("url = ", url)
        
        # 获取来源
        source_text = text_html.xpath('//*[@id="fontinfo"]/p[last()]//text()')[0]
        source = source_text[3:]
        
        # 爬取文本
        text_list = text_html.xpath('//*[@id="fontinfo"]//text()')
        article_text = "".join(text_list).replace('\r\n','').replace("\xa0", "").replace("\t", "").replace(source_text,"").replace(title, "")    
        # print ("article_text", article_text)
        # print ("source = ", source)
        writer.writerow((title, publish_time, url, article_text, source))
    except:
        pass
    
    if url == 'http://www.chinanpo.gov.cn/1944/123496/index.html':
        fp.close()
        # 获取结束时的时间
        endTime =time.time()           
        useTime =(endTime-startTime)/60
        print ("该次所获的信息一共使用%s分钟"%useTime)
        # 正常退出程序
        sys.exit(0)       
    else:
        return next_url

#----------------------------------------------主函数----------------------------------------------
def main():
    url = "http://www.chinanpo.gov.cn/1944/125177/nextindex.html" # 125177第一篇文章
    count = 1
    while True:
        print ("正在爬取第%s篇:"%count, url)
        next_url = spider_html_info(url)
        url = next_url
        count = count + 1
                
if __name__ == '__main__':
    main()

抓取的结果如下图所示:

在这里插入图片描述

在这里插入图片描述

读者可能需要安装扩展包lxml和fake_useragent。

在这里插入图片描述



二.中文分词及高频词统计

1.结巴分词

数据预处理是指在进行数据分析之前,对数据进行的一些初步处理,包括缺失值填写、噪声处理、不一致数据修正、中文分词等,其目标是得到更标准、高质量的数据,纠正错误异常数据,从而提升分析的结果。中文文本预处理的基本步骤,包括中文分词、词性标注、数据清洗、特征提取(向量空间模型存储)、权重计算(TF-IDF)等。

“结巴”(Jieba)工具是最常用的中文文本分词和处理的工具之一,它能实现中文分词、词性标注、关键词抽取、获取词语位置等功能。其在Github网站上的介绍及下载地址为:https://github.com/fxsjy/jieba

调用命令“pip install jieba”安装jieba中文分词包如下图所示。

pip install jieba

在这里插入图片描述

Jieba具有以下特点:

  • 支持三种分词模式,包括精确模式、全模式和搜索引擎模式
  • 支持繁体分词
  • 支持自定义词典
  • 代码对Python2和Python3均兼容
  • 支持多种编程语言,包括Java、C++、Rust、PHP、R、Node.js等


2.基本用法

首先读者看一段简单的结巴分词代码,主要调用两个函数实现。

  • jieba.cut(text, cut_all=True)
    分词函数,第一个参数是需要分词的字符串,第二个参数表示是否为全模式。分词返回的结果是一个可迭代的生成器(generator),可使用for循环来获取分词后的每个词语,更推荐读者转换为list列表再使用。
  • jieba.cut_for_search(text)
    搜索引擎模式分词,参数为分词的字符串,该方法适合用于搜索引擎构造倒排索引的分词,粒度比较细。
#encoding=utf-8  
import jieba  
  
text = "小杨毕业于北京理工大学,从事Python人工智能相关工作。"  

#全模式
data = jieba.cut(text,cut_all=True)
print(type(data))
print(u"[全模式]: ", "/".join(data))

#精确模式  
data = jieba.cut(text,cut_all=False)
print(u"[精确模式]: ", "/".join(data))

#默认是精确模式 
data = jieba.cut(text)  
print(u"[默认模式]: ", "/".join(data))

#搜索引擎模式 
data = jieba.cut_for_search(text)    
print(u"[搜索引擎模式]: ", "/".join(data))

#返回列表
seg_list = jieba.lcut(text, cut_all=False)
print("[返回列表]: {0}".format(seg_list))

输出结果如下图所示:

在这里插入图片描述



3.获取疫情文本高频词

接着我们将新闻正文文本“C-class.txt”数据进行中文分词,每行代表一条新闻,并生成对应的内容。

# coding=utf-8
import jieba
import re
import time
from collections import Counter

#------------------------------------中文分词------------------------------------
cut_words = ""
all_words = ""
f = open('C-class-fenci.txt', 'w')
for line in open('C-class.txt', encoding='utf-8'):
    line.strip('\n')
    seg_list = jieba.cut(line,cut_all=False)
    # print(" ".join(seg_list))
    cut_words = (" ".join(seg_list))
    f.write(cut_words)
    all_words += cut_words
else:
    f.close()

# 输出结果
all_words = all_words.split()
print(all_words)

# 词频统计
c = Counter()
for x in all_words:
    if len(x)>1 and x != '\r\n':
        c[x] += 1

# 输出词频最高的前10个词
print('\n词频统计结果:')
for (k,v) in c.most_common(10):
    print("%s:%d"%(k,v))

# 存储数据
name = time.strftime("%Y-%m-%d") + "-fc.csv"
fw = open(name, 'w', encoding='utf-8')
i = 1
for (k,v) in c.most_common(len(c)):
    fw.write(str(i)+','+str(k)+','+str(v)+'\n')
    i = i + 1
else:
    print("Over write file!")
    fw.close()

输出结果如下图所示,采用空格连接的分词结果。

在这里插入图片描述

同时生成高频特征词,并保存至CSV文件中。

在这里插入图片描述

对应的特征词及词频排序如表“2020-03-06-fc.csv”所示,如果我们撰写图情论文,可以尝试建立Top50的特征词表。

在这里插入图片描述



三.WordCloud可视化分析

1.基本用法

词云分析主要包括两种方法:

  • 调用WordCloud扩展包画图(兼容性极强,之前介绍过)
  • 调用PyEcharts中的WordCloud子包画图(本文推荐新方法)

前一篇文章作者详细讲解了PyEcharts可视化相关用法,这里我们需要通过它来绘制词云,基础代码如下:

# coding=utf-8
from pyecharts import options as opts
from pyecharts.charts import WordCloud
from pyecharts.globals import SymbolType

# 数据
words = [
    ('背包问题', 10000),
    ('大整数', 6181),
    ('Karatsuba乘法算法', 4386),
    ('穷举搜索', 4055),
    ('傅里叶变换', 2467),
    ('状态树遍历', 2244),
    ('剪枝', 1868),
    ('Gale-shapley', 1484),
    ('最大匹配与匈牙利算法', 1112),
    ('线索模型', 865),
    ('关键路径算法', 847),
    ('最小二乘法曲线拟合', 582),
    ('二分逼近法', 555),
    ('牛顿迭代法', 550),
    ('Bresenham算法', 462),
    ('粒子群优化', 366),
    ('Dijkstra', 360),
    ('A*算法', 282),
    ('负极大极搜索算法', 273),
    ('估值函数', 265)
]

# 渲染图
def wordcloud_base() -> WordCloud:
    c = (
        WordCloud()
        .add("", words, word_size_range=[20, 100], shape='diamond')  # SymbolType.ROUND_RECT
        .set_global_opts(title_opts=opts.TitleOpts(title='WordCloud词云'))
    )
    return c

# 生成图
wordcloud_base().render('词云图.html')

输出结果如下图所示,出现词频越高显示越大。

在这里插入图片描述

核心代码为:
add(name, attr, value, shape=“circle”, word_gap=20, word_size_range=None, rotate_step=45)

  • name -> str: 图例名称
  • attr -> list: 属性名称
  • value -> list: 属性所对应的值
  • shape -> list: 词云图轮廓,有’circle’, ‘cardioid’, ‘diamond’, ‘triangleforward’, ‘triangle’, ‘pentagon’, ‘star’可选
  • word_gap -> int: 单词间隔,默认为20
  • word_size_range -> list: 单词字体大小范围,默认为[12,60]
  • rotate_step -> int: 旋转单词角度,默认为45


2.疫情词云

接着我们显示经过中文分词的疫情新闻文本信息,前1000个高频词的词云绘制代码如下:

# coding=utf-8
import jieba
import re
import time
from collections import Counter

#------------------------------------中文分词------------------------------------
cut_words = ""
all_words = ""
f = open('C-class-fenci.txt', 'w')
for line in open('C-class.txt', encoding='utf-8'):
    line.strip('\n')
    seg_list = jieba.cut(line,cut_all=False)
    # print(" ".join(seg_list))
    cut_words = (" ".join(seg_list))
    f.write(cut_words)
    all_words += cut_words
else:
    f.close()

# 输出结果
all_words = all_words.split()
print(all_words)

# 词频统计
c = Counter()
for x in all_words:
    if len(x)>1 and x != '\r\n':
        c[x] += 1

# 输出词频最高的前10个词
print('\n词频统计结果:')
for (k,v) in c.most_common(10):
    print("%s:%d"%(k,v))

# 存储数据
name = time.strftime("%Y-%m-%d") + "-fc.csv"
fw = open(name, 'w', encoding='utf-8')
i = 1
for (k,v) in c.most_common(len(c)):
    fw.write(str(i)+','+str(k)+','+str(v)+'\n')
    i = i + 1
else:
    print("Over write file!")
    fw.close()

#------------------------------------词云分析------------------------------------
from pyecharts import options as opts
from pyecharts.charts import WordCloud
from pyecharts.globals import SymbolType

# 生成数据 word = [('A',10), ('B',9), ('C',8)] 列表+Tuple
words = []
for (k,v) in c.most_common(1000):
    # print(k, v)
    words.append((k,v))

# 渲染图
def wordcloud_base() -> WordCloud:
    c = (
        WordCloud()
        .add("", words, word_size_range=[20, 100], shape=SymbolType.ROUND_RECT)
        .set_global_opts(title_opts=opts.TitleOpts(title='全国新型冠状病毒疫情词云图'))
    )
    return c

# 生成图
wordcloud_base().render('疫情词云图.html')

输出结果如下图所示:

在这里插入图片描述



四.TF-IDF计算及KMeans文本聚类

1.TF-IDF计算

TF-IDF(Term Frequency-InversDocument Frequency)是一种常用于信息处理和数据挖掘的加权技术。该技术采用一种统计方法,根据字词的在文本中出现的次数和在整个语料中出现的文档频率来计算一个字词在整个语料中的重要程度。它的优点是能过滤掉一些常见的却无关紧要本的词语,同时保留影响整个文本的重要字词。计算方法如下面公式所示:

T F I D F = T F I D F TF-IDF = TF* IDF

TF(Term Frequency)表示某个关键词在整篇文章中出现的频率。IDF(InversDocument Frequency)表示计算倒文本频率。文本频率是指某个关键词在整个语料所有文章中出现的次数。倒文档频率又称为逆文档频率,它是文档频率的倒数,主要用于降低所有文档中一些常见却对文档影响不大的词语的作用。

TF-IDF统计可视化完整代码如下:

# coding=utf-8 
import os
import time
import pandas as pd
import numpy as np
import jieba
import jieba.analyse
import matplotlib.pyplot as plt
from PIL import Image
from datetime import datetime
from matplotlib.font_manager import FontProperties

#------------------------------------中文分词------------------------------------
cut_words = ""
for line in open('C-class.txt', encoding='utf-8'):
    line.strip('\n')
    seg_list = jieba.cut(line,cut_all=False)
    # print(" ".join(seg_list))
    cut_words += (" ".join(seg_list))

# jieba.load_userdict("userdict.txt")              # 自定义词典
# jieba.analyse.set_stop_words('stop_words.txt')   # 停用词词典

# 提取主题词 返回的词频其实就是TF-IDF
keywords = jieba.analyse.extract_tags(cut_words,
                                      topK=50,
                                      withWeight=True,
                                      allowPOS=('a','e','n','nr','ns', 'v')) #词性 形容词 叹词 名词 动词

# 以列表形式返回
print(keywords)

# 数据存储
pd.DataFrame(keywords, columns=['词语','重要性']).to_excel('TF_IDF关键词前50.xlsx')

# keyword本身包含两列数据
ss = pd.DataFrame(keywords,columns = ['词语','重要性'])     
# print(ss)

#------------------------------------数据可视化------------------------------------
plt.figure(figsize=(10,6))
plt.title('TF-IDF Ranking')
fig = plt.axes()
plt.barh(range(len(ss.重要性[:25][::-1])),ss.重要性[:25][::-1])
fig.set_yticks(np.arange(len(ss.重要性[:25][::-1])))
font = FontProperties(fname=r'c:\windows\fonts\simsun.ttc')
fig.set_yticklabels(ss.词语[:25][::-1],fontproperties=font)
fig.set_xlabel('Importance')
plt.show()

输出结果如下图所示,可以看到“疫情”、“组织”、“捐赠”、“社会”、“协会”、“肺炎”、“物资”等都是高频词,也是大众普遍关心的主题。

在这里插入图片描述

注意:可能需要安装openpyxl扩展包,to_excel()函数要用到。
在这里插入图片描述



2.文本聚类

同样,在Scikit-Learn包中也能计算TF-IDF权重值,此时需要用到两个类:CountVectorizer和TfidfTransformer。

(1) CountVectorizer
CountVectorizer类会将文本中的词语转换为词频矩阵,例如矩阵中包含一个元素a[i][j],它表示j词在i类文本下的词频。它通过fit_transform函数计算各个词语出现的次数,通过get_feature_names()可获取词袋中所有文本的关键字,通过toarray()可看到词频矩阵的结果。

(2) TfidfTransformer
TfidfTransformer用于统计vectorizer中每个词语的TF-IDF值。具体用法如下:

# coding:utf-8
from sklearn.feature_extraction.text import CountVectorizer
 
#语料
corpus = [
    'This is the first document.',
    'This is the second second document.',
    'And the third one.',
    'Is this the first document?',
]
#将文本中的词语转换为词频矩阵
vectorizer = CountVectorizer()
#计算个词语出现的次数
X = vectorizer.fit_transform(corpus)
#获取词袋中所有文本关键词
word = vectorizer.get_feature_names()
print word
#查看词频结果
print X.toarray()
 
from sklearn.feature_extraction.text import TfidfTransformer
 
#类调用
transformer = TfidfTransformer()
print transformer
#将词频矩阵X统计成TF-IDF值
tfidf = transformer.fit_transform(X)
#查看数据结构 tfidf[i][j]表示i类文本中的tf-idf权重
print tfidf.toarray()

输出结果入下所示,从结果中可以看到,总共包括9个特征词,即:
[u’and’, u’document’, u’first’, u’is’, u’one’, u’second’, u’the’, u’third’, u’this’]

同时在输出每个句子中包含特征词的个数。例如,第一句“This is the first document.”,它对应的词频为[0, 1, 1, 1, 0, 0, 1, 0, 1],假设初始序号从1开始计数,则该词频表示存在第2个位置的单词“document”共1次、第3个位置的单词“first”共1次、第4个位置的单词“is”共1次、第9个位置的单词“this”共1词。所以,每个句子都会得到一个词频向量,TF-IDF对应向量类似。

在这里插入图片描述


(3) 文本聚类

# coding=utf-8  
import time          
import re          
import os  
import sys
import codecs
import shutil
import numpy as np
import matplotlib
import scipy
import matplotlib.pyplot as plt
from sklearn import feature_extraction  
from sklearn.feature_extraction.text import TfidfTransformer  
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import HashingVectorizer 

if __name__ == "__main__":

    #########################################################################
    #                           第一步 计算TFIDF
    
    # 文档预料 空格连接
    corpus = []
    
    # 读取预料 一行预料为一个文档
    for line in open('C-class-fenci.txt', 'r').readlines():
        corpus.append(line.strip())
    
    # 将文本中的词语转换为词频矩阵 矩阵元素a[i][j] 表示j词在i类文本下的词频
    vectorizer = CountVectorizer()
 
    # 该类会统计每个词语的tf-idf权值
    transformer = TfidfTransformer()
 
    # 第一个fit_transform是计算tf-idf 第二个fit_transform是将文本转为词频矩阵
    tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))
 
    # 获取词袋模型中的所有词语  
    word = vectorizer.get_feature_names()
    
    # 将tf-idf矩阵抽取出来 元素w[i][j]表示j词在i类文本中的tf-idf权重
    weight = tfidf.toarray()
 
    # 打印特征向量文本内容
    print('Features length: ' + str(len(word)))
    
    """
    # 输出单词
    for j in range(len(word)):
        print(word[j] + ' ')
        
    # 打印每类文本的tf-idf词语权重 第一个for遍历所有文本 第二个for便利某一类文本下的词语权重  
    for i in range(len(weight)):
        print u"-------这里输出第", i, u"类文本的词语tf-idf权重------"  
        for j in range(len(word)):
            print weight[i][j],
    """

    ########################################################################
    #                               第二步 聚类Kmeans
 
    print('Start Kmeans:')
    from sklearn.cluster import KMeans
    clf = KMeans(n_clusters=2)
    print(clf)
    pre = clf.fit_predict(weight)
    print(pre)

    #中心点
    print(clf.cluster_centers_)
    print(clf.inertia_)
    
    ########################################################################
    #                               第三步 图形输出 降维
 
    from sklearn.decomposition import PCA
    pca = PCA(n_components=2)             #输出两维
    newData = pca.fit_transform(weight)   #载入N维
    print(newData)
    
    x = [n[0] for n in newData]
    y = [n[1] for n in newData]
    
    plt.scatter(x, y, c=pre, s=100)
    plt.legend()
    plt.title("Cluster with Text Mining")
    plt.show()

输出结果如下图所示。需要注意,简单的聚类我们无法进行深入的分析,你可以理解为积极主题的一类(黄色)、消极主题的一类(黑色),也可以有其他理解,需要结合具体数据集进行分析,但其解释性始终不是很好。而真实的数据分析中会引入类标或标注,所以接着我们引入主题关键词聚类和LDA主题模型的分析,更能帮助大家理解文本挖掘和主题分析。

在这里插入图片描述



五.主题词层次聚类分析

1.层次聚类

层次聚类算法又称为树聚类算法,它根据数据之间的距离,透过一种层次架构方式,反复将数据进行聚合,创建一个层次以分解给定的数据集。主题词层次聚类主要调用scipy.cluster.hierarchy实现,推荐文章:层次聚类

  • scipy.cluster.hierarchy.linkage(y, method=‘single’, metric=‘euclidean’, optimal_ordering=False)

层次聚类编码为一个linkage矩阵。假设代码如下,Z共有四列组成,第一字段与第二字段分别为聚类簇的编号,在初始距离前每个初始值被从0~n-1进行标识,每生成一个新的聚类簇就在此基础上增加一对新的聚类簇进行标识,第三个字段表示前两个聚类簇之间的距离,第四个字段表示新生成聚类簇所包含的元素的个数。

from scipy.cluster.hierarchy import dendrogram, linkage,fcluster
from matplotlib import pyplot as plt
X = [[i] for i in [2, 8, 0, 4, 1, 9, 9, 0]]
print(X)
Z = linkage(X, 'ward')
f = fcluster(Z, 4, 'distance')
fig = plt.figure(figsize=(5, 3))
dn = dendrogram(Z)
plt.show()

下面是聚类结果的可视化聚类树:

在这里插入图片描述

下面是返回值的解析:

在这里插入图片描述



2.疫情分析

由于层次聚类绘制的树状图主题词太多,所以这里采用中文分词提取每条新闻(对应一行数据)的Top100特征词,再存储至TXT中进行层次聚类分析。完整代码如下:

# -*- coding: utf-8 -*-
import os
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import jieba
import matplotlib.pyplot as plt
from pylab import mpl
from collections import Counter
from sklearn.metrics.pairwise import cosine_similarity
from scipy.cluster.hierarchy import ward, dendrogram
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer

mpl.rcParams['font.sans-serif'] = ['SimHei']

#------------------------------ 第一步 计算TOP100 ------------------------------
# 计算中文分词词频TOP100
cut_words = ""
all_words = ""
for line in open('C-class.txt', encoding='utf-8'):
    line.strip('\n')
    seg_list = jieba.cut(line,cut_all=False)
    # print(" ".join(seg_list))
    cut_words = (" ".join(seg_list))
    all_words += cut_words
    
# 输出结果
all_words = all_words.split()
print(all_words)

# 词频统计
c = Counter()
for x in all_words:
    if len(x)>1 and x != '\r\n':
        c[x] += 1

# 输出词频最高的前10个词
top_word = []
print('\n词频统计结果:')
for (k,v) in c.most_common(100):
    print("%s:%d"%(k,v))
    top_word.append(k)
print(top_word)
# ['疫情', '防控', '组织', '工作'...]

#------------------------------ 第二步 中文分词过滤 ------------------------------
# 过滤
cut_words = ""
f = open('C-key.txt', 'w')
for line in open('C-class.txt', encoding='utf-8'):
    line.strip('\n')
    seg_list = jieba.cut(line,cut_all=False)
    final = ""
    for seg in seg_list:
        if seg in top_word:
            final += seg + "|"
    cut_words += final
    f.write(final+"\n")
print(cut_words)
f.close

#------------------------------ 第三步 相相关计算 ------------------------------ 
text = open('C-key.txt').read()
list1 = text.split("\n")
print(list1)

# 数据第一行、第二行数据
# print(list1[0])
# print(list1[1])
mytext_list = list1

# min_df用于删除不经常出现的术语
# max_df用于删除过于频繁出现的术语,也称为语料库特定的停用词
# count_vec = CountVectorizer(min_df=3, max_df=3)
count_vec = CountVectorizer(min_df=3)
xx1 = count_vec.fit_transform(list1).toarray()
word = count_vec.get_feature_names() 
print("word feature length: {}".format(len(word)))
print(word)
print(xx1.shape)
print(xx1[0])
titles = word

#------------------------------ 第四步 相似度计算 ------------------------------ 
df = pd.DataFrame(xx1)
print(df.corr())
print(df.corr('spearman'))
print(df.corr('kendall'))

dist = df.corr()
print(dist)
print(type(dist))
print(dist.shape)

#------------------------------ 第五步 可视化分析 ------------------------------ 
# define the linkage_matrix using ward clustering pre-computed distances
linkage_matrix = ward(dist)
fig, ax = plt.subplots(figsize=(15, 20)) # set size
ax = dendrogram(linkage_matrix, orientation="right", labels=titles);

# how plot with tight layout
plt.tight_layout() 

# save figure as ward_clusters
plt.savefig('Tree_word.png', dpi=200) 

最终生成图像如下所示:

在这里插入图片描述

在这里插入图片描述

运行结果如下图所示:

在这里插入图片描述

注意:该方法更推荐大家在进行论文关键词共现分析、主题词聚类分析等领域。



六.LDA主题分布分析

1.LDA主题模型

文档主题生成模型(Latent Dirichlet Allocation,简称LDA)通常由包含词、主题和文档三层结构组成。LDA模型属于无监督学习技术,它是将一篇文档的每个词都以一定概率分布在某个主题上,并从这个主题中选择某个词语。文档到主题的过程是服从多项分布的,主题到词的过程也是服从多项分布的。

文档主题生成模型(Latent Dirichlet Allocation,简称LDA)又称为盘子表示法(Plate Notation),下图是模型的标示图,其中双圆圈表示可测变量,单圆圈表示潜在变量,箭头表示两个变量之间的依赖关系,矩形框表示重复抽样,对应的重复次数在矩形框的右下角显示。LDA模型的具体实现步骤如下:

  • 从每篇网页D对应的多项分布θ中抽取每个单词对应的一个主题z。
  • 从主题z对应的多项分布φ中抽取一个单词w。
  • 重复步骤1和2,共计Nd次,直至遍历网页中每一个单词。

在这里插入图片描述

读者可以从gensim中下载ldamodel扩展包安装,也可以使用Sklearn机器学习包的LDA子扩展包,亦可从github中下载开源的LDA工具。下载地址详见列表所示。

来源 下载地址
gensim https://radimrehurek.com/gensim/models/ldamodel.html
scikit-learn 利用pip install sklearn命令安装扩展包,LatentDirichletAllocation函数即LDA原型
github https://github.com/ariddell/lda

本文和之前介绍的LDA算法略有不同,它主要采用sklearn中的LatentDirichletAllocation包实现主题分布研究,并调用pyLDAvis绘制相关图形。安装过程如下所示:

在这里插入图片描述



2.完整代码

#coding: utf-8
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizer

#---------------------  第一步 读取数据(已分词)  ----------------------
corpus = []

# 读取预料 一行预料为一个文档
for line in open('C-class-fenci.txt', 'r').readlines():
    corpus.append(line.strip())
        
#-----------------------  第二步 计算TF-IDF值  ----------------------- 
# 设置特征数
n_features = 2000

tf_vectorizer = TfidfVectorizer(strip_accents = 'unicode',
                                max_features=n_features,
                                stop_words=['的','或','等','是','有','之','与','可以','还是','比较','这里',
                                            '一个','和','也','被','吗','于','中','最','但是','图片','大家',
                                            '一下','几天','200','还有','一看','300','50','哈哈哈哈',
                                             '“','”','。',',','?','、',';','怎么','本来','发现',
                                             'and','in','of','the','我们','一直','真的','18','一次',
                                           '了','有些','已经','不是','这么','一一','一天','这个','这种',
                                           '一种','位于','之一','天空','没有','很多','有点','什么','五个',
                                           '特别'],
                                max_df = 0.99,
                                min_df = 0.002) #去除文档内出现几率过大或过小的词汇

tf = tf_vectorizer.fit_transform(corpus)

print(tf.shape)
print(tf)

#-------------------------  第三步 LDA分析  ------------------------ 
from sklearn.decomposition import LatentDirichletAllocation

# 设置主题数
n_topics = 2

lda = LatentDirichletAllocation(n_components=n_topics,
                                max_iter=100,
                                learning_method='online',
                                learning_offset=50,
                                random_state=0)
lda.fit(tf)

# 显示主题数 model.topic_word_
print(lda.components_)
# 几个主题就是几行 多少个关键词就是几列 
print(lda.components_.shape)                         

# 计算困惑度
print(u'困惑度:')
print(lda.perplexity(tf,sub_sampling = False))

# 主题-关键词分布
def print_top_words(model, tf_feature_names, n_top_words):
    for topic_idx,topic in enumerate(model.components_):  # lda.component相当于model.topic_word_
        print('Topic #%d:' % topic_idx)
        print(' '.join([tf_feature_names[i] for i in topic.argsort()[:-n_top_words-1:-1]]))
        print("")

# 定义好函数之后 暂定每个主题输出前20个关键词
n_top_words = 20                                       
tf_feature_names = tf_vectorizer.get_feature_names()
# 调用函数
print_top_words(lda, tf_feature_names, n_top_words)


#------------------------  第四步 可视化分析  ------------------------- 
import pyLDAvis
import pyLDAvis.sklearn

#pyLDAvis.enable_notebook()

data = pyLDAvis.sklearn.prepare(lda,tf,tf_vectorizer)
print(data)

#显示图形
pyLDAvis.show(data)

#pyLDAvis.save_json(data,' fileobj.html')

困惑度及各个主题下的关键词通过for循环显示如下,Topic1是疫情相关的主题词,Topic0是其他相关的主题。

(1149, 2000)

[[ 0.55751432  0.54567562  0.55251776 ...  0.53834991  0.54686374
   0.54566266]
 [ 6.01547264  2.6540167  15.00664759 ...  5.00509822  8.88753264
   3.76198499]]
(2, 2000)
困惑度:
1825.1911194848506
Topic #0:
思源 工程 新华书店 中华 咨询师 供应商 扶贫 南安市 贵州省 旅游 新华 名称 主席 秘书长 清关 服务项目 万双 联系人 理事长 资讯

Topic #1:
疫情 防控 组织 社会 工作 协会 捐赠 企业 服务 万元 物资 社区 慈善 积极 会员 做好 肺炎 防疫 商会 口罩

生成对应的图形浏览器会打开,如下图所示:

在这里插入图片描述


在这里插入图片描述


注意:LDA主题分布分析需要设置不同的主题值,这里是2,也可以是3、4、5等等。那么如何确定最佳主题数呢?困惑数又有什么用呢?如果存在语义知识又怎么处理呢?主题如何能更加准确定位呢?读者可以带着这些思考去探索。加油~



七.总结

写到这里,第三篇疫情分析的文章就讲解完毕,希望对您有所帮助,尤其是想写文本挖掘论文的读者。主要包括两部分内容:

  • 实时数据爬取
  • 中文文本分词及高频词提取
  • 词云可视化分析
  • TF-IDF权重计算和文本聚类分析
  • 层次聚类分析
  • LDA主题模型分布

后续还会分享情感分析、舆情分析、主题挖掘、威胁情报溯源、知识图谱、预测预警及AI和NLP应用等。如果文章对您有所帮助,将是我写作的最大动力。作者将源代码上传至github,大家可以直接下载。你们的支持就是我撰写的最大动力,加油~

在这里插入图片描述

同时,向钟院士致敬,向一线工作者致敬。侠之大者,为国为民。咱们中国人一生的最高追求,为天地立心,为生民立命,为往圣继绝学,为万世开太平。以一人之力系万民康乐,以一身犯险保大业安全。他们真是做到了,武汉加油,中国加油!

在这里插入图片描述

(By:Eastmount 2020-03-07 中午12点于贵阳 http://blog.csdn.net/eastmount/)



参考文献:
[1] [python数据挖掘课程] 十三.WordCloud词云配置过程及词频分析 - Eastmount
[2] [python] LDA处理文档主题分布代码入门笔记 - Eastmount
[3] [python] Kmeans文本聚类算法+PAC降维+Matplotlib显示聚类图像 - Eastmount
[4] [python] 使用Jieba工具中文分词及文本聚类概念 - Eastmount
[5] [原创博文] 教你使用Pyecharts绘制词云图 - 浮世若离
[6] 用pyecharts绘制词云WordCloud - pennyyangpei
[7] 用Python pyecharts v1.x 绘制图形(二):折线图、折线面积图、散点图、雷达图、箱线图、词云图 - 蒜泥的冬天
[8] [python数据挖掘课程] 二十八.基于LDA和pyLDAvis的主题挖掘及可视化分析 - Eastmount
[9] Python层次聚类sci.cluster.hierarchy.linkage函数详解 - tan_handsome

发布了439 篇原创文章 · 获赞 5781 · 访问量 477万+

猜你喜欢

转载自blog.csdn.net/Eastmount/article/details/104698926
今日推荐