数据包下载

由于数据包太大,请大家前往搜狗站点下载。

传送门:搜狗新闻数据包下载

引入Jieba分词和WordCloud词云包

Python大数据基础 利用Jieba分词分析搜狗新闻并生成WordCloud词云请大家先尝试imort jieba和import wordcloud

如果无法引入包的话按以下步骤安装

按Win+R键,键入cmd回车进入命令行界面。

键入pip install jieba

等待安装完成后

键入pip install WordCloud

由于博主已经安装过了,就不提供详细截图了。

等待安装完成后再次尝试imort jieba和import wordcloud如果可以引入包就成功安装了。

流程分析

词云的几个常用方法

wordcloud.WordCloud() //词云的构造方法,相关参数请参考下表

参数 默认值 说明
font_path 字体路径,需要展现什么字体就把该字体路径+后缀名写上,如:font_path = '黑体.ttf'
width 400 输出的画布宽度,默认为400像素
height 200 输出的画布高度,默认为200像素
prefer_horizontal 0.90 词语水平方向排版出现的频率,默认 0.9 (所以词语垂直方向排版出现频率为 0.1 )
mask None 如果参数为空,则使用矩形罩绘制词云。如果 mask 非空,设置的宽高值将被忽略,遮罩形状被 mask 取代。除全白(#FFFFFF)的部分将不会绘制,其余部分会用于绘制词云。
scale 1 按照比例进行放大画布,如设置为1.5,则长和宽都是原来画布的1.5倍。
min_font_size 4 显示的最小的字体大小
font_step 1 字体步长,如果步长大于1,会加快运算但是可能导致结果出现较大的误差。
max_words 200 要显示的词的最大个数
stopwords STOPWORDS 设置需要屏蔽的词,如果为空,则使用内置的STOPWORDS
background_color black 背景颜色,如background_color='white',背景颜色为白色。
max_font_size None 显示的最大的字体大小
mode RGB 当参数为“RGBA”并且background_color不为空时,背景为透明。
relative_scaling .5 词频和字体大小的关联性
color_func None 生成新颜色的函数,如果为空,则使用 self.color_func
regexp 使用正则表达式分隔输入的文本
collocations True 是否包括两个词的搭配
colormap viridis 给每个单词随机分配颜色,若指定color_func,则忽略该方法。

fit_words(frequencies) //根据词频生成词云【frequencies,为字典类型】

generate(text) //根据文本生成词云

generate_from_frequencies(frequencies[, ...]) //根据词频生成词云

generate_from_text(text) //根据文本生成词云

process_text(text) //将长文本分词并去除屏蔽词(此处指英语,中文分词还是需要自己用别的库先行实现,使用上面的 fit_words(frequencies) )

recolor([random_state, color_func, colormap]) //对现有输出重新着色。重新上色会比重新生成整个词云快很多。

to_array() //转化为 numpy array

to_file(filename) //输出到文件

设计思路

1.要处理数据,首先要读入数据。一般来说,直接将全部读入后处理即可,但是由于本次要处理的数据包太大。如果全部读入,会占用太多内存,甚至可能出现崩溃。所以,应想办法一部分一部分的读,每读一部分就处理一部分。在本例中,博主采用了按行读取的方式。每读一行,便对该行分词,并用字典统计词语出现的次数。

2.统计完词语后对词语进行过滤操作,过滤掉没有用的词。

3.依据词汇字典生成词云并保存词云图片。

4.为了以后方便使用可以在统计完词语后将统计后的词语字典保存到本地,下次使用可以直接调用保存好的词语字典去生成词云(该步骤可选)。

创建Python项目

将搜狗新闻数据包加入到项目

将下载的搜狗新闻数据包解压出来重命名为word.dat,移动到项目目录下即可

编写代码

function.py
# -*- coding: utf-8 -*-
'''
Created on Sat Oct 12 10:43:39 2019

@author: KX
@site:www.newview.top
仅供参考,禁止抄袭
'''

import wordcloud
import jieba
import datetime
from wordcloud import ImageColorGenerator

def wordCount(fileName):
    #统计文本中的词汇
    def caculateAllLine(fileName):
        #计算文本的总行数
        print("计算总行数中...")
        f = open(fileName, "rb")
        lineAll = 0
        for index, line in enumerate(f):
            lineAll += 1
        print('文本共%d行.'%lineAll)
        f.close()
        return lineAll
    
    def processText(text,words):
        #统计一行单词
        
        ##############筛选要处理的标签 开始##############################
        #如果处理其他不需筛选的文本的话(例如电子书) 可以将这部分删掉
        #获取标签长度
        tagLength = text.index(b'>')-1;
        
        #获取标签名
        textType = text[1:tagLength+1]
        
        #筛选 contenttitle和content标签 如果不是这两个标签 则直接return
        if textType != b"contenttitle" and textType != b"content":
            return 
        
        #获取标签内容
        text = text[tagLength+2:-tagLength-3]
        ##############筛选要处理的标签 结束##############################
        
        #分词处理
        wordsArr = jieba.lcut(text, cut_all=False)
        
        #统计词汇
        for name in wordsArr:
            #if len(name) <= 1:
            #    continue
            if name not in words:
                words[name] = 1
            else:
                words[name] = words[name] + 1
    
    
    #计算要处理的文本的总行数
    lineAll = caculateAllLine(fileName)

    print("打开文本中...")
    f = open(fileName, "rb")

    print("处理文本中...")
    
    #用于统计词汇出现的次数
    words = dict()
    
    #用于记录读取的行数
    lineCount = 1;
    try:  
        #记录开始执行的时间
        startTime = datetime.datetime.now()
        while True:
            
            #读取一行文本
            text = f.readline()
            
            #如果没有读取完
            if text:
                
                if lineCount%10000 == 0:
                    #每读10000行显示一次进度
                    
                    #获取现在时间
                    nowTime = datetime.datetime.now()
                    
                    #计算已完成进度
                    finishedRatio = lineCount/lineAll
                    
                    #计算已花费时间
                    usedTime = (nowTime-startTime).seconds
                    
                    #计算剩余时间
                    remainTime = (usedTime/finishedRatio)-usedTime
                    print("处理文本中. 进度:%.2f%% 预计剩余时间:%02d:%02d:%02d 已用时间:%02d:%02d:%02d"
                          %(finishedRatio*100,remainTime/3600
                            ,(remainTime/60)%60,remainTime%60
                            ,usedTime/3600,(usedTime/60)%60,usedTime%60))
                
                #处理一行文本
                processText(text,words)
                lineCount = lineCount + 1
            else:
                break
    finally:
        print("文本处理完成...")
        f.close()
    return words

def generateWordCloud(words,maskFile,fontPath,scale=32,maxWords=200): 
    print("生成词云中...")
    import numpy as np
    from PIL import Image
    
    #生成图形遮罩
    mask = np.array(Image.open(maskFile))
    genclr = ImageColorGenerator(mask)
    
    #生成词云
    wc = wordcloud.WordCloud(
                   font_path = fontPath,#字体
                   background_color = "white",  # 背景颜色
                   min_font_size = 5,#最小字体大小
                   max_words = maxWords,  # 词云显示的最大词数
                   mask = mask, #造型遮盖
                   scale = scale, #画布大小
                   relative_scaling = 0.4 #词频和字体大小的关联性
    )
    wc.generate_from_frequencies(frequencies = words);
    
    #对词云重新上色
    wc.recolor(color_func = genclr)
    fileName = "wordCloud_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + ".jpg"
    
    #保存词云文件
    wc.to_file(fileName)
    print("词云图片已保存至"+fileName)
    return fileName

def getDictFromFile(fileName):
    #读取本地缓存,简单写的,Python版本不同可能会不适用
    print("读取词汇缓存中...")
    #如果有词汇缓存就直接读缓存 就不用再次处理文本了
    f = open(fileName, "r")
    words = dict()
    try:
        char = "";
        isEnd = False
        while True:
            word = ""#本次读取的词语
            num = 0#本次词语的出现次数
            
            while f.read(1)!="'":
                #读一个字符
                #没有读到词语开始的单引号则继续读下一个字符
                #知道读到词语开始的位置
                continue
                
            while True:
                #读词语
                char = f.read(1);
                if char =="'":
                    #读到单引号说明词语结束
                    break;
                else:
                    word += char
                    
            while f.read(1)!=":":
                #读一个字符
                #没有读到次数开始的单引号则继续读下一个字符
                #知道读到次数开始的位置
                continue
            
            while True:
                #读取次数
                char = f.read(1)
                if "0"<= char <= "9":
                    num = num*10 + int(char)
                elif char==",":
                    #读到了,或}说明次数结束
                    break
                elif char==" ":
                    #读到空格跳过
                    continue
                elif char=="}":
                    isEnd = True
                    break
            words[word] = num
            if isEnd:
                break
    finally:
        f.close();
    return words

def putDictToFile(fileName,words):
    #将词汇字典写入文件 方便以后直接引用
    print("将词汇内容写入缓存中...")
    f = open(fileName, "w")
    f.write(str(words));
    f.close();

def filterStopWords(words,stopWordsFileName):
    print("过滤停用词中...")
    
    #过滤长度为1的词和\开头的词
    for word in list(words):
        if len(word)==1 or word[0]=='\\':
            words.pop(word)
    
    #过滤停用词
    f = open(stopWordsFileName,"rb")
    stopWord = f.readline()
    while stopWord:
        
        #strip():清空后面的\r\n   decode():将字节串转化为字符串
        stopWord = stopWord.strip().decode()
        if stopWord in words:
            words.pop(stopWord)
        stopWord = f.readline()
    f.close()
    return words
WordAnalyze.py
# -*- coding: utf-8 -*-
"""
Created on Sat Oct 12 10:43:39 2019

@author: KX
@site:www.newview.top
!!!仅供参考,禁止抄袭!!!
"""

import function as f
import os


print("开始运行...")

#要处理的文件名
fileName="words.dat"

#判断是否存在本地词汇统计缓存
if os.path.exists("Dict_"+fileName):
    #存在则直接读取缓存
    words = f.getDictFromFile("Dict_"+fileName)
else:
    #不存在则需要对文本进行分词、统计等处理
    
    #文本进行分词、统计等处理
    words = f.wordCount(fileName)
    #将处理完的词汇统计字典写入本地缓存,下次就不用再次处理文本了
    f.putDictToFile("Dict_"+fileName,words)


#过滤停用词
words = f.filterStopWords(words,"stopWords.txt")

#生成词云
wordCloud = f.generateWordCloud(words=words,maxWords=300,maskFile="china.jpg",fontPath=r'C:\Windows\Fonts\STLITI.TTF',scale=8)
print("自动为您打开图片中...")

#完成后自动打开图片
os.system(wordCloud)

print("运行结束")

运行

开始运行

Python大数据基础 利用Jieba分词分析搜狗新闻并生成WordCloud词云

大概等了3个小时左右....

Python大数据基础 利用Jieba分词分析搜狗新闻并生成WordCloud词云

我们要的终于出来了!

Python大数据基础 利用Jieba分词分析搜狗新闻并生成WordCloud词云

没关系,这是第一次运行。由于博主在本代码加入了词汇统计缓存机制,以后再次运行就不用分析文本了,可以直接读取缓存文件,本来3个小时的工作在10s内就能完成了!

其他问题

由于编码问题无法打开文件

打开文件的时候无需去管他的编码,直接用二进制方式打开即可。也就是:f=open("words.dat","rb");

读取时内存飙升至99%

由于本次要处理的数据包太大。如果全部读入,会占用太多内存,甚至可能出现崩溃。所以,应想办法一部分一部分的读,每读一部分就处理一部分。

有关词云中文出现方框乱码

出现中文方框乱码的原因是默认的字体不支持中文,参考上表设定一下WordCloud方法的font_path参数即可。

去除停用词的实现原理

由于统计后会出现很多无用的单词,因此需要对单词进行过滤操作。

本例将所有的停用词保存到一个文件内,统计完单词频率后,遍历停用词从单词字典中将其删除(可以通过字典类的pop方法)。

附上停用词文件:stopWords.txt

中国地图的图案是如何实现的

参考上表设定一下WordCloud方法的mask参数即可。

附上中国原版图:

Python大数据基础 利用Jieba分词分析搜狗新闻并生成WordCloud词云

 


我一直在开辟我的天空