TOP

机器学习 - 文本分析案例 - 新闻分析

文本分析概念

停用词

语料中大量出现, 无用数据, 如下类似的这种词语

Tf  - 词频统计

 

TF 的计算方式有很多, 最常见的用 某词文章中出现次数 / 文章总词数

 

idf  - 逆文档频率

TF - idf   关键词提取

相似度

分词

语料库

词频

词频向量

整体流程 

语料清洗 (去掉停用词, 去掉大量重复的非正常用语等)

计算公式

文本分析案例 - 新闻分析

样本数据

数据来源于 搜狗实验室新闻数据  

数据需要处理成  pandas 便于读取的数据才可以使用

import pandas as pd 
import jieba

df_news = pd.read_table('./data/val.txt',names=['category','theme','URL','content'],encoding='utf-8')
df_news = df_news.dropna() # 去除缺失值行
df_news.head()

样本数据结构

样本数据容量

df_news.shape #(5000, 4)

分词 - 使用结巴分词器

读取数据

结巴分词器需要传入的数据为 list , 这里进行一个转换

content = df_news.content.values.tolist()
print (type(content)) # <class 'list'>
print(content[1000])
阿里巴巴集团昨日宣布,将在集团管理层面设立首席数据官岗位(Chief Data Officer),阿里巴巴B2B公司CEO陆兆禧将会出任上述职务,向集团CEO马云直接汇报。>菹ぃ和6月初的首席风险官职务任命相同,首席数据官亦为阿里巴巴集团在完成与雅虎股权谈判,推进“one company”目标后,在集团决策层面新增的管理岗位。0⒗锛团昨日表示,“变成一家真正意义上的数据公司”已是战略共识。记者刘夏

分词处理

content_S = []
for line in content:
    current_segment = jieba.lcut(line)
    if len(current_segment) > 1 and current_segment != '\r\n': #换行符
        content_S.append(current_segment)
content_S[1000]
['阿里巴巴',
 '集团',
 '昨日',
 '宣布',
 '',
 '',
 '',
 '集团',
 '管理',
 '层面',
 '设立',
 '首席',
 '数据',
 '',
 '岗位',
 '',
 '',
 '',
 '',
 '',
 '',
 '\u3000',
 '',
 '',
 '',
 '',
 '\u3000',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '阿里巴巴',
 '',
 '',
 '',
 '公司',
 '',
 '',
 '',
 '陆兆禧',
 '',
 '',
 '出任',
 '上述',
 '职务',
 '',
 '',
 '集团',
 '',
 '',
 '',
 '马云',
 '直接',
 '汇报',
 '',
 '',
 '',
 '',
 '',
 '',
 '月初',
 '',
 '首席',
 '风险',
 '',
 '职务',
 '任命',
 '相同',
 '',
 '首席',
 '数据',
 '官亦为',
 '阿里巴巴',
 '集团',
 '',
 '完成',
 '',
 '雅虎',
 '股权',
 '谈判',
 '',
 '推进',
 '',
 '',
 '',
 '',
 '\u3000',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '',
 '目标',
 '',
 '',
 '',
 '集团',
 '决策',
 '层面',
 '新增',
 '',
 '管理',
 '岗位',
 '',
 '',
 '',
 '',
 '',
 '昨日',
 '表示',
 '',
 '',
 '变成',
 '一家',
 '真正',
 '意义',
 '',
 '',
 '数据',
 '公司',
 '',
 '',
 '',
 '战略',
 '共识',
 '',
 '记者',
 '刘夏']
content_S[1000]

分词数据

df_content=pd.DataFrame({'content_S':content_S})
df_content.head()

数据清洗

停用词表

通用词表下载后直接读取进来即可

stopwords=pd.read_csv("stopwords.txt",index_col=False,sep="\t",quoting=3,names=['stopword'], encoding='utf-8')
stopwords.head(5)

去除停用词

def drop_stopwords(contents,stopwords):
    contents_clean = []
    all_words = []
    for line in contents:
        line_clean = []
        for word in line:
            if word in stopwords:
                continue
            line_clean.append(word) # 没过滤掉的加入到列表
            all_words.append(str(word)) # 做词云用的列表
        contents_clean.append(line_clean)
    return contents_clean,all_words
    #print (contents_clean)
        

contents = df_content.content_S.values.tolist()   # 分词后正文转列表 
stopwords = stopwords.stopword.values.tolist()  # 通用词转列表
contents_clean,all_words = drop_stopwords(contents,stopwords)

去除后停用词后的分词数据

df_content=pd.DataFrame({'contents_clean':contents_clean})
df_content.head()

 可以对比之前的未去除的数据, 可以看出很多常用词都被去除了

可以看出 一些字母还是没有去除掉, 如果有需要是可以在停用词表中计入即可

词云数据

词云数据是所有出现的非停用词的一个总的统计, 这里一起转换成df结构

df_all_words=pd.DataFrame({'all_words':all_words})
df_all_words.head()

词频展示

词频计算

根据 all_words 分组后添加新一列 count 计数

然后根据 count 排序进行词频的计算

import numpy

words_count=df_all_words.groupby(by=['all_words'])['all_words'].agg({"count":numpy.size})
words_count=words_count.reset_index().sort_values(by=["count"],ascending=False)
words_count.head()

词云展示

from wordcloud import WordCloud
import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib
matplotlib.rcParams['figure.figsize'] = (10.0, 5.0)

wordcloud=WordCloud(font_path="./data/simhei.ttf",background_color="white",max_font_size=80)
word_frequence = {x[0]:x[1] for x in words_count.head(100).values} # 前 100 个词进行展示
wordcloud=wordcloud.fit_words(word_frequence)
plt.imshow(wordcloud)

关键词提取

 jieba.analyse.extract_tags  方法可以对关键词进行提取, 指定提取数量

import jieba.analyse
index = 1000
print (df_news['content'][index])
content_S_str = "".join(content_S[index])  
print()
print ("  ".join(jieba.analyse.extract_tags(content_S_str, topK=5, withWeight=False)))
阿里巴巴集团昨日宣布,将在集团管理层面设立首席数据官岗位(Chief Data Officer),阿里巴巴B2B公司CEO陆兆禧将会出任上述职务,向集团CEO马云直接汇报。>菹ぃ和6月初的首席风险官职务任命相同,首席数据官亦为阿里巴巴集团在完成与雅虎股权谈判,推进“one company”目标后,在集团决策层面新增的管理岗位。0⒗锛团昨日表示,“变成一家真正意义上的数据公司”已是战略共识。记者刘夏

阿里巴巴  集团  首席  岗位  数据

LDA 主题模型

LDA(Latent Dirichlet Allocation)是一种文档主题生成模型,它是一种主题模型,它包含文章,主题和词三个部分,它可以将文档集中每篇文档的主题以概率分布的形式给出,从而通过分析一些文档抽取出它们的主题(分布)出来后,便可以根据主题(分布)进行主题聚类或文本分类。同时,它是一种典型的词袋模型,即一篇文档是由一组词构成,词与词之间没有先后顺序的关系。此外,一篇文档可以包含多个主题,文档中每一个词都由其中的一个主题生成。LDA就是要干的事就是根据给定的一篇文档,推测其主题分布。它是一个无监督学习,类似于聚类。

引入模块

from gensim import corpora, models, similarities
import gensim

格式要求

格式要求是 list of list 形式,分词好的的整个语料

最外层的列表盛放多个文章, 内部的每个列表盛放分好词的数据

映射处理

#做映射,相当于生成一个大字典, 每个词进行一个映射唯一的标识符
dictionary = corpora.Dictionary(contents_clean)
corpus = [dictionary.doc2bow(sentence) for sentence in contents_clean] # 语料

建模

建模的时候可以指定主题数量

# 类似Kmeans自己指定K值
lda = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=20) 

展示结果

查看一号分类的前5名的主题, 以及全部的分类中的主题前5名

因为语料库的本身数量级问题导致确实得出的解雇非常不理想就是了

#一号分类结果
print (lda.print_topic(1, topn=5))
0.006*"" + 0.004*"观众" + 0.003*"" + 0.003*"中国" + 0.003*""
for topic in lda.print_topics(num_topics=20, num_words=5):
    print (topic[1])
0.014*"中国" + 0.007*"" + 0.006*"评委" + 0.005*"" + 0.005*""
0.006*"" + 0.004*"观众" + 0.003*"" + 0.003*"中国" + 0.003*""
0.010*"孩子" + 0.004*"家长" + 0.004*"" + 0.004*"" + 0.003*""
0.007*"" + 0.006*"赛区" + 0.005*"学校" + 0.005*"万元" + 0.004*""
0.012*"电影" + 0.008*"票房" + 0.005*"上映" + 0.005*"影迷" + 0.004*"影片"
0.008*"" + 0.007*"" + 0.006*"" + 0.004*"" + 0.004*""
0.007*"" + 0.005*"欧洲杯" + 0.004*"" + 0.003*"工作" + 0.003*""
0.009*"" + 0.006*"" + 0.005*"电影" + 0.003*"工作" + 0.003*"观众"
0.013*"男人" + 0.009*"卫视" + 0.008*"女人" + 0.008*"孩子" + 0.007*""
0.010*"电影" + 0.009*"陈坤" + 0.008*"主演" + 0.007*"剧组" + 0.005*""
0.004*"决赛" + 0.003*"" + 0.003*"生母" + 0.002*"" + 0.002*""
0.020*"考生" + 0.004*"学校" + 0.003*"" + 0.003*"" + 0.003*"院校"
0.010*"" + 0.005*"比赛" + 0.004*"肌肤" + 0.004*"" + 0.003*""
0.011*"饰演" + 0.008*"" + 0.008*"比赛" + 0.007*"男人" + 0.005*""
0.008*"节目" + 0.006*"" + 0.006*"" + 0.005*"" + 0.005*""
0.008*"" + 0.006*"中国" + 0.005*"" + 0.004*"导演" + 0.003*""
0.041*"" + 0.035*"" + 0.029*"" + 0.027*"" + 0.027*""
0.006*"" + 0.005*"" + 0.005*"" + 0.004*"演出" + 0.003*""
0.005*"" + 0.004*"" + 0.004*"中国" + 0.003*"" + 0.003*""
0.006*"中国" + 0.005*"" + 0.003*"球队" + 0.003*"" + 0.003*""

利用贝叶斯进行分类

数据准备

将分好词的数据和每个文章的主题分类进行组合成 DF 数据结构

df_train=pd.DataFrame({'contents_clean':contents_clean,'label':df_news['category']})
df_train.tail()

 

 分类数据映射

df_train.label.unique()
array(['汽车', '财经', '科技', '健康', '体育', '教育', '文化', '军事', '娱乐', '时尚'],
      dtype=object)

所有的主题分类就是以下的这些, 中文数据在 DF 里面是没法识别的, 因此转换成数字更容易处理

将映射用  map  进行替换

label_mapping = {"汽车": 1, "财经": 2, "科技": 3, "健康": 4, "体育":5, "教育": 6,"文化": 7,"军事": 8,"娱乐": 9,"时尚": 0}
df_train['label'] = df_train['label'].map(label_mapping)
df_train.head()

 

划分数据集

数据集还是正常操作的切分为训练集和测试集

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(
    df_train['contents_clean'].values, 
    df_train['label'].values, 
    random_state=1)

特征提取成向量结构准备

简单的一个 demo 展示  CountVectorizer 构造器的使用

指定 参数  ngram_range 之后可以对现有的词进行增加组合频率然后识别处理,

这样的会生成的向量更加负杂, 测试demo 如下, 通常指定为 2维 即可 

通过上面的 两个demo 可以看出构造器接受的数据结构为 list, 每个元素表示每个文章

list 内部元素为 字符串, 字符串内包含分词数据, 用空格隔开

最开始的时候我们的结构是 list of list 因此需要将 内部的 list 转换成 空格间隔的 str

words = []
for line_index in range(len(x_train)):
    try:
        #x_train[line_index][word_index] = str(x_train[line_index][word_index])
        words.append(' '.join(x_train[line_index]))
    except:
        print (line_index,word_index)
words[0]      

处理后的结构

'中新网 上海 日电 于俊 父亲节 网络 吃 一顿 电影 快餐 微 电影 爸 对不起 我爱你 定于 本月 父亲节 当天 各大 视频 网站 首映 葜 谱 鞣 剑 保慈 障蚣 钦 呓 樯 埽 ⒌ 缬 埃 ǎ 停 椋 悖 颍 铩 妫 椋 恚 称 微型 电影 新 媒体 平台 播放 状态 短时 休闲 状态 观看 完整 策划 系统 制作 体系 支持 显示 较完整 故事情节 电影 微 超短 放映 微 周期 制作 天 数周 微 规模 投资 人民币 几千 数万元 每部 内容 融合 幽默 搞怪 时尚 潮流 人文 言情 公益 教育 商业 定制 主题 单独 成篇 系列 成剧 唇 开播 微 电影 爸 对不起 我爱你 讲述 一对 父子 观念 缺少 沟通 导致 关系 父亲 传统 固执 钟情 传统 生活 方式 儿子 新派 音乐 达 习惯 晚出 早 生活 性格 张扬 叛逆 两种 截然不同 生活 方式 理念 差异 一场 父子 间 拉开序幕 子 失手 打破 父亲 心爱 物品 父亲 赶出 家门 剧情 演绎 父亲节 妹妹 哥哥 化解 父亲 这场 矛盾 映逋坏 嚼 斫 狻 ⒍ 粤 ⒌ 桨容 争执 退让 传统 尴尬 父子 尴尬 情 男人 表达 心中 那份 感恩 一杯 滤挂 咖啡 父亲节 变得 温馨 镁 缬 缮 虾 N 逄 煳 幕 传播 迪欧 咖啡 联合 出品 出品人 希望 观摩 扪心自问 父亲节 父亲 记得 父亲 生日 哪一天 父亲 爱喝 跨出 家门 那一刻 感觉 一颗 颤动 心 操劳 天下 儿女 父亲节 大声 喊出 父亲 家人 爱 完'

特征提取成向量

from sklearn.feature_extraction.text import CountVectorizer

vec = CountVectorizer(analyzer='word', max_features=4000,  lowercase = False)
vec.fit(words)

构造出的模型如下

CountVectorizer(analyzer='word', binary=False, decode_error='strict',
                dtype=<class 'numpy.int64'>, encoding='utf-8', input='content',
                lowercase=False, max_df=1.0, max_features=4000, min_df=1,
                ngram_range=(1, 1), preprocessor=None, stop_words=None,
                strip_accents=None, token_pattern='(?u)\\b\\w\\w+\\b',
                tokenizer=None, vocabulary=None)

贝叶斯计算训练

传入的参数是刚刚特征提取后的词频向量作为 x , 然后 y 是之前 map 过的主题分类

from sklearn.naive_bayes import MultinomialNB
classifier = MultinomialNB()
classifier.fit(vec.transform(words), y_train)

生成的模型

MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)

贝叶斯测试

测试的时候测试集的数据也要和训练时使用的数据格式相同

test_words = []
for line_index in range(len(x_test)):
    try:
        #x_train[line_index][word_index] = str(x_train[line_index][word_index])
        test_words.append(' '.join(x_test[line_index]))
    except:
         print (line_index,word_index)
test_words[0]
'国家 公务员 考试 申论 应用文 类 试题 实质 一道 集 概括 分析 提出 解决问题 一体 综合性 试题 说 一道 客观 凝练 申发 论述 文章 题目 分析 历年 国考 申论 真题 公文 类 试题 类型 多样 包括 公文 类 事务性 文书 类 题材 从题 干 作答 材料 内容 整合 分析 无需 太 创造性 发挥 纵观 历年 申论 真题 作答 应用文 类 试题 文种 格式 作出 特别 重在 内容 考查 行文 格式 考生 平常心 面对 应用文 类 试题 准确 把握 作答 领会 内在 含义 把握 题材 主旨 材料 结构 轻松 应对 应用文 类 试题 R 弧 ⒆ 钒 盐 展文 写作 原则 T 材料 中来 应用文 类 试题 材料 总体 把握 客观 考生 材料 中来 材料 中 把握 材料 准确 理解 题材 主旨 T 政府 角度 作答 应用文 类 试题 更应 注重 政府 角度 观点 政府 角度 出发 原则 表述 观点 提出 解决 之策 考生 作答 站 政府 人员 角度 看待 提出 解决问题 T 文体 结构 形式 考查 重点 文体 结构 大部分 评分 关键点 解答 方法 薄 ⒆ ス 丶 词 明 方向 作答 题目 题干 作答 作答 方向 作答 角度 关键 向导 考生 仔细阅读 题干 作答 抓住 关键词 作答 方向 相关 要点 整理 作答 思路 年国考 地市级 真 题为 例 潦惺姓 府 宣传 推进 近海 水域 污染 整治 工作 请 给定 资料 市政府 工作人员 身份 草拟 一份 宣传 纲要 R 求 保对 宣传 内容 要点 提纲挈领 陈述 玻 体现 政府 精神 全市 各界 关心 支持 污染 整治 工作 通俗易懂 超过 字 肮 丶 词 近海 水域 污染 整治 工作 市政府 工作人员 身份 宣传 纲要 提纲挈领 陈述 体现 政府 精神 全市 各界 关心 支持 污染 整治 工作 通俗易懂 提示 归结 作答 要点 包括 污染 情况 原因 解决 对策 作答 思路 情况 原因 对策 意义 逻辑 顺序 安排 文章 结构 病 ⒋ 缶殖 龇 ⅲ 明 结构 解答 应用文 类 试题 考生 材料 整体 出发 大局 出发 高屋建瓴 把握 材料 主题 思想 事件 起因 解决 对策 阅读文章 构建 文章 结构 直至 快速 解答 场 ⒗ 硭 乘悸 罚明 逻辑 应用文 类 试题 严密 逻辑思维 情况 原因 对策 意义 考生 作答 先 弄清楚 解答 思路 统筹安排 脉络 清晰 逻辑 表达 内容 表述 础 把握 明 详略 考生 仔细阅读 分析 揣摩 应用文 类 试题 内容 答题 时要 详略 得当 主次 分明 安排 内容 增加 文章 层次感 阅卷 老师 阅卷 时能 明白 清晰 一目了然 玻埃 保蹦旯 考 考试 申论 试卷 分为 省级 地市级 两套 试卷 能力 大有 省级 申论 试题 考生 宏观 角度看 注重 深度 广度 考生 深谋远虑 地市级 试题 考生 微观 视角 观察 侧重 考查 解决 能力 考生 贯彻执行 作答 区别对待'

查看使用  CountVectorizer  构造的特征向量数据预测准确率, 得到结果是 0.804 

classifier.score(vec.transform(test_words), y_test)
0.804

换一个TFidf 的特征提取器, 查看是否会有变化

from sklearn.feature_extraction.text import TfidfVectorizer

vectorizer = TfidfVectorizer(analyzer='word', max_features=4000,  lowercase = False)
vectorizer.fit(words)

进行训练测试

from sklearn.naive_bayes import MultinomialNB
classifier = MultinomialNB()
classifier.fit(vectorizer.transform(words), y_train)
classifier.score(vectorizer.transform(test_words), y_test)

预测准确率为 0.815 , 可以看出  CountVectorizer  比起  TfidfVectorizer  还是要有点区别的

0.81520000000000004

 

posted @ 2019-11-18 16:40  羊驼之歌  阅读(2383)  评论(0编辑  收藏  举报