【原创】python词云分析陈粒和赵雷

作者: _SoLo_ | 来源:发表于2018-06-30 22:16 被阅读19次

    未经同意禁止转载,否则通过维权骑士追究

    【完整源代码请点击 此处 留言以获取,可以顺便给颗Star😄】

    记录一个练习小项目,训练一下python分析技能。用到的知识有“爬虫”、“jieba分词”、“wordcloud词云”、“Tableau可视化”

    准备环境

    spyder

    直接使用anaconda中的spyder IDE,毕竟anaconda管理各种组件、包非常方便

    python

    python版本为3.6.4,之前参考网上不少资料,很多代码是用python2写的,比如unicode在python3中已经没有了
    但有些博文中的读取txt文件部分,仍用的python2方法,且不注明环境。千古文章一大抄

    jieba

    jieba库没有被anaconda收录,所以需要自己去下载安装,是zip格式
    直接解压到D:\Anaconda\pkgs 目录下,打开 Anaconda Prompt并cd进入jieba解压目录,执行python setup.py install

    wordcloud

    这个地方遇到不少问题,因为我没安装vs,不具有vc编译环境,所以直接从github上下载wordcloud的压缩包执行python setup.py install直接报错了!
    去网上查了下资料,发现是缺少一个vc-build-tool下载安装需要4G左右(ps:坑爹啊)
    后来在wordcloud的github主页上找到了安装whl文件(已经被编译过)的替代方法

    whl

    whl格式本质上是一个压缩包,里面包含了py文件,以及经过编译的pyd文件。使得可以在不具备编译环境的情况下,选择合适自己的python环境进行安装。
    安装方法很简单,进入命令行输入
    pip install xxxx.whl
    或者如果是升级
    pip install -U xxxx.whl

    流程概述

    • 爬取歌词,保存为txt文件
    • bat命令,合并同一个歌手所有txt文件(建立一个bat文件,内容为 type *.txt >> all.txt,编码和源文件相同)
    • 对合并的歌词txt文件,调用jieba进行分词
    • 针对分词的结果绘制词云图
    • 统计分词结果,Tableau进行结果展示分析

    爬取歌词

    在download_lyric(1007170)这句中改歌手ID1007170即可爬取其他歌手的全部歌曲歌词
    歌词源来自网易云音乐;从歌手主页上爬取网易收录的该歌手所有歌曲

    
    
    
    def get_html(url):
        headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36'}
        try:
            response = requests.get(url, headers=headers)
            html = response.content
            return html
        except:
            print('request error')
            pass
    
    def download_by_music_id(music_id):
        lrc_url = 'http://music.163.com/api/song/lyric?'+'id='+str(music_id) + '&lv=1&kv=1&tv=-1'
        r = requests.get(lrc_url)
        json_obj = r.text
        j = json.loads(json_obj)
        try:
            lrc = j['lrc']['lyric']
            pat = re.compile(r'\[.*\]')
            lrc = re.sub(pat, "",lrc)
            lrc = lrc.strip()
            return lrc
        except:
            pass
    
    def get_music_ids_by_musician_id(singer_id):
        singer_url = 'http://music.163.com/artist?id={}'.format(singer_id)
        r = get_html(singer_url)
        soupObj = BeautifulSoup(r,'lxml')
        song_ids = soupObj.find('textarea').text
        jobj = json.loads(song_ids)
        ids = {}
        for item in jobj:
            print(item['id'])
            ids[item['name']] = item['id']
        return ids
    
    def download_lyric(uid):
        try:
            os.mkdir(str(uid))
        except:
            pass
    
        os.chdir(str(uid))
        music_ids = get_music_ids_by_musician_id(uid)
        for key in music_ids:
            text = download_by_music_id(music_ids[key])        
            file = open(key+'.txt', 'a', encoding='ansi')  #创建的文本以ansi编码
            file.write(key+'\n')
            file.write(str(text))
            file.close()
    
    if __name__ == '__main__':
        download_lyric(1007170)     #只需要在这里更改网易云音乐web网站上,歌手主页url后的ID即可,比如陈粒是1007170
    

    jieba分词

    参考

    添加自定义词典(usr_dict)

    • 开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词。虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率
    • 用法: jieba.load_userdict(file_name) # file_name 为文件类对象或自定义词典的路径
    • 词典格式和 dict.txt 一样,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。file_name 若为路径或二进制方式打开的文件,则文件必须为 UTF-8 编码。
    • 词频省略时使用自动计算的能保证分出该词的词频。

    添加忽略词语(stop_word)

    • 主要思想是分词过后,遍历一下停用词表,去掉停用词。
    #!/usr/bin/env python3
    #遇到的编码字符流问题参考了如下博客的解决方案
    #https://blog.csdn.net/zhangyunfei_happy/article/details/47169939
    jieba.load_userdict('usr_dict.txt')
    def stopwordslist(filepath):
        stopwords = [line.strip() for line in open(filepath, 'r',encoding='utf-8').readlines()]
        return stopwords
    
    # 对句子进行分词
    def seg_sentence(sentence):
        sentence_seged = jieba.cut(sentence.strip())
        stopwords = stopwordslist('stop_word.txt')  # 这里加载停用词的路径
        outstr = ''
        for word in sentence_seged:
            if word not in stopwords:
                if word != '\t':
                    outstr += word
                    outstr += " "
        return outstr
    
    if __name__ == '__main__':
        
       
        inputs = open('all.txt', 'r',encoding='ansi')  #源文件是'utf-8'编码,
        outputs = open('all_outputs.txt', 'w',encoding='utf-8')  #保存为utf8编码
        for line in inputs:
            line_seg = seg_sentence(line)  # 这里的返回值是字符串
            #注意有些符号是中英文两种格式,所以都要包含进去
            line_seg = re.sub("[A-Za-z0-9\[\`\~\!\@\#\$\^\&\*\(\)\=\|\{\}\'\:\;\'\,\[\]\.\<\>\/\?\~\!\@\#\\\&\*\%\:\(\)]", "", line_seg)
            outputs.write(line_seg)
            outputs.write('\n')
        outputs.close()
        inputs.close()
    

    wordcloud词云

    选择背景图片,颜色最好对比分明,不然生成的词图,轮廓不明显

    # coding: utf-8
    import re
    import jieba
    from scipy.misc import imread  # 这是一个处理图像的函数
    from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
    
    import matplotlib.pyplot as plt
    #选择背景图片,颜色最好对比分明,不然生成的词图,轮廓不明显
    back_color = imread('chenli.jpg')  # 解析该图片
    
    # WordCloud各含义参数请点击 wordcloud参数
    wc = WordCloud(background_color='white',  # 背景颜色
                   max_words=1000,  # 最大词数
                   mask=back_color,  # 以该参数值作图绘制词云,这个参数不为空时,width和height会被忽略
                   max_font_size=100,  # 显示字体的最大值
                   stopwords=STOPWORDS.add(' '),  # 使用内置的屏蔽词,再添加'苟利国'
                   font_path="C:/Windows/Fonts/msyhbd.ttc",  # 显示中文,从属性里复制字体名称,不能直接看windows显示的字体名
                   random_state=42,  # 为每个词返回一个PIL颜色
                   # width=1000,  # 图片的宽
                   # height=860  #图片的长
                   )
    
    
    # 添加自己的词库分词,比如添加'陈粒啊'到jieba词库后,当你处理的文本中含有“陈粒啊”这个词,
    # 就会直接将'陈粒啊'当作一个词,而不会得到'陈粒'或'粒啊'这样的词
    jieba.add_word('陈粒啊')
    
    # 打开词源的文本文件,加read以字符串的形式
    txt = open('all_outputs.txt','r',encoding='UTF-8').read()
    # 去除文本中的英文,特殊符号等,只保留中文
    txt = re.sub("[A-Za-z0-9\[\`\~\!\@\#\$\^\&\*\(\)\=\|\{\}\'\:\;\'\,\[\]\.\<\>\/\?\~\!\@\#\\\&\*\%]", "", txt)
    
    # 该函数的作用就是把屏蔽词去掉,使用这个函数就不用在WordCloud参数中添加stopwords参数了
    # 把你需要屏蔽的词全部放入一个stopwords文本文件里即可
    def stop_words(texts):
        words_list = []
        word_generator = jieba.cut(texts, cut_all=False)  # 返回的是一个迭代器
        with open('stop_word.txt','r',encoding='UTF-8') as f:
            str_text = f.read()
            #print(str_text)  #如果不知道解码是否正确,可print一下,看输出的中文是否乱码
            f.close()  # stopwords文本中词的格式是'一词一行'
        for word in word_generator:
            if word.strip() not in str_text:
                words_list.append(word)
        return ' '.join(words_list)  # 注意是空格
    
    # 分词统计
    把分词后的结果按`词语+频数`的格式保存为txt和excel文件,方便Tableau处理加工
    ``` python
    # -*- coding:utf-8 -*-
    import sys, jieba, jieba.analyse, xlwt
    if __name__ == "__main__":
        wbk = xlwt.Workbook(encoding='ascii')
        sheet = wbk.add_sheet("wordCount")  # Excel单元格名字
        word_lst = []
        key_list = []
        for line in open('all_outputs.txt', 'rb'):  # 1.txt是需要分词统计的文档
            item = line.strip('\n\r'.encode('utf-8')).split('\t'.encode('utf-8'))  # 制表格切分
           
            tags = jieba.analyse.extract_tags(item[0])  # jieba分词
            for t in tags:
                word_lst.append(t)
        word_dict = {}
        with open("wordCount.txt", 'bw') as wf2:  # 打开文件
            for item in word_lst:
                if item not in word_dict:  # 统计数量
                    word_dict[item] = 1
                else:
                    word_dict[item] += 1
            orderList = list(word_dict.values())
            orderList.sort(reverse=True)
            # print orderList
            for i in range(len(orderList)):
                for key in word_dict:
                    if word_dict[key] == orderList[i]:
                        wf2.write((key + ' ' + str(word_dict[key])).encode('utf-8'))  # 写入txt文档
                        wf2.write('\n'.encode('utf-8'))  # 写入txt文档
                        key_list.append(key)
                        word_dict[key] = 0
    
        for i in range(len(key_list)): #为了便于tableau限量统计,可改为 for i in range(200),限定200个词
            sheet.write(i, 1, label=orderList[i])
            sheet.write(i, 0, label=key_list[i])
        wbk.save('wordCount.xls')  # 保存为 wordCount.xls文件
    

    结果展示

    获取的歌词文件

    进行分词

    分词统计

    词云

    陈粒.png

    陈粒的词云


    赵雷.png

    赵雷的词云

    Tableau可视化

    赵雷统计.png

    赵雷的歌词频数统计


    陈粒统计.png

    陈粒的歌词频数统计


    对比.png

    陈、赵歌词相似度统计

    遇到的问题

    wordcloud命名问题

    File "E:\CZK\工作\数据分析\我的练习项目\词云项目\wordcloud.py", line 5, in <module>
        from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
    ImportError: cannot import name 'WordCloud'
    

    解决办法

    从wordcloud作者的github及stackoverflow上均找到了答案,不得不说google搜索大法好!
    改py文件的名字,就是不要以“wordcloud”命名你的py文件

    包未编译问题

      File "E:/CZK/工作/数据分析/我的练习项目/词云项目/get_wordcloud.py", line 4, in <module>
        from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
    ModuleNotFoundError: No module named 'wordcloud'
    

    解决办法

    下载whl文件,http://www.lfd.uci.edu/~gohlke/pythonlibs/#wordcloud
    然后 pip install <whl文件名>

    编码和读取文件

    AttributeError: '_io.TextIOWrapper' object has no attribute 'decode' 
    

    解决办法

    jieba.cut第一个参数为str不是file,所以open文件时需要有.read()
    另外读取,存储文本时,要注意源文件编码,encoding=xxxx,具体可阅读源代码

    相关文章

      网友评论

        本文标题:【原创】python词云分析陈粒和赵雷

        本文链接:https://www.haomeiwen.com/subject/gsyxuftx.html