文本分析
停用词
语料中大量出现,但没有大的用处
Tf-idf 关键词提取
T F − I D F = 词 频 ( T F ) ∗ 逆 文 档 频 率 ( I D F ) TF-IDF = 词频(TF)*逆文档频率(IDF) TF−IDF=词频(TF)∗逆文档频率(IDF)
假设拿到一个文章:《中国的蜜蜂养殖》
进行词频(Term Frequency,缩写为TF)统计
词 频 ( T F ) = 某 个 词 在 文 章 中 的 出 现 次 数 该 文 章 中 总 词 量 词频(TF) = \frac{某个词在文章中的出现次数}{该文章中总词量} 词频(TF)=该文章中总词量某个词在文章中的出现次数
统计出现次数最多的词是 “的”、“是”、“在” 这一类最常用的词(停用词)由此可见,停用词对我们做词频统计有比较大的影响,我们首先就要去掉这些停用词,去掉停用词后,再作统计,结果显示“中国”、“蜜蜂”、“养殖”这三个词的出现次数一样多,但重要性不同,因为"中国"是很常见的词,相对而言,"蜜蜂"和"养殖"不那么常见,所以本文题主应该是与"蜜蜂"和"养殖"有较大的关系
“逆文档频率”(Inverse Document Frequency,缩写为IDF)
如果某个词比较少见,但是它在这篇文章中多次出现,那么它很可能就反映了这篇文章的特性正是我们所需要的关键词
逆 文 档 频 率 ( I D F = l o g ( 语 料 库 的 文 档 总 数 包 含 该 词 的 文 档 数 + 1 ) ) 逆文档频率(IDF=log(\frac{语料库的文档总数}{包含该词的文档数+1})) 逆文档频率(IDF=log(包含该词的文档数+1语料库的文档总数))
IDF越大,该词越重要
例子:
《中国的蜜蜂养殖》:假定该文长度为1000个词,“中国”、“蜜蜂”、“养殖"各出现20次,则这三个词的"词频”(TF)都为0.02
搜索Google发现,包含"的"字的网页共有250亿张,假定这就是中文网页总数。包含"中国"的网页共有62.3亿张,包含"蜜蜂"的网页为0.484亿张,包含"养殖"的网页为0.973亿张
\ | 包含该词的文档数(亿) | IDF | TF-IDF |
---|---|---|---|
中国 | 62.3 | 0.603 | 0.0121 |
蜜蜂 | 0.484 | 2.713 | 0.0543 |
养殖 | 0.973 | 2.410 | 0.0482 |
通过表格可以发现,“蜜蜂”、“养殖”的TF-IDF比较高,证明比较重要
相似度
假设句子A/B:
句子A:我喜欢看电视,不喜欢看电影
句子B:我不喜欢看电视,也不喜欢看电影
分词:
句子A:我/喜欢/看/电视,不/喜欢/看/电影
句子B:我/不/喜欢/看/电视,也/不/喜欢/看/电影
语料库:
我,喜欢,看,电视,电影,不,也
词频:
句子A:我 1,喜欢 2,看 2,电视 1,电影 1,不 1,也 0
句子B:我 1,喜欢 2,看 2,电视 1,电影 1,不 2,也 1
词频向量:
句子A:[1, 2, 2, 1, 1, 1, 0]
句子B:[1, 2, 2, 1, 1, 2, 1]
计算相似度公式:
余弦相似度
c
o
s
θ
=
∑
i
=
1
n
(
A
i
∗
B
i
)
∑
i
=
1
n
(
A
i
)
2
∗
∑
i
=
1
n
B
i
2
=
A
∗
B
∣
A
∣
∗
∣
B
∣
cos\theta = \frac{\sum_{i=1}^n(A_i*B_i)}{\sqrt{\sum_{i=1}^n(A_i)^2}*\sum_{i=1}^n{B_i}^2}=\frac{A*B}{|A|*|B|}
cosθ=∑i=1n(Ai)2∗∑i=1nBi2∑i=1n(Ai∗Bi)=∣A∣∗∣B∣A∗B
新闻数据
读取数据
import pandas as pd
df_news = pd.read_table('./data/val.txt',names=['category','theme','URL','content'],encoding='utf-8')
df_news = df_news.dropna()
df_news.head()
分词:使用结吧分词器
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)
# 转换为df类型
df_content=pd.DataFrame({'content_S':content_S})
# 读入停用词
stopwords=pd.read_csv("stopwords.txt",index_col=False,sep="\t",quoting=3,names=['stopword'], encoding='utf-8')
数据清洗,去掉停用词
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
# 执行清洗
contents = df_content.content_S.values.tolist()
stopwords = stopwords.stopword.values.tolist()
contents_clean,all_words = drop_stopwords(contents,stopwords)
# 转换为df格式
df_content=pd.DataFrame({'contents_clean':contents_clean})
统计词频
import numpy
df_all_words=pd.DataFrame({'all_words':all_words})
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)
使用 WordCloud,对所有词中的高词频做一个词云展示
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}
wordcloud=wordcloud.fit_words(word_frequence)
plt.imshow(wordcloud)
关键词提取
TF-IDF :提取关键词
import jieba.analyse
index = 1000
print (df_news['content'][index])
content_S_str = "".join(content_S[index])
# jieba.analyse.extract_tags 提取关键词 topK=* 返回*个
print (" ".join(jieba.analyse.extract_tags(content_S_str, topK=5, withWeight=False)))
阿里巴巴集团昨日宣布,将在集团管理层面设立首席数据官岗位(Chief Data Officer),阿里巴巴B2B公司CEO陆兆禧将会出任上述职务,向集团CEO马云直接汇报。>菹ぃ和6月初的首席风险官职务任命相同,首席数据官亦为阿里巴巴集团在完成与雅虎股权谈判,推进“one company”目标后,在集团决策层面新增的管理岗位。0⒗锛团昨日表示,“变成一家真正意义上的数据公司”已是战略共识。记者刘夏
阿里巴巴 集团 首席 岗位 数据
LDA :主题模型
使用 Gensim 构建 LDA 模型 Gensim官方API文档
格式要求:list of list形式,分词好的的整个语料
建模
import gensim
from gensim import corpora, models, similarities
# 做映射,相当于词袋
dictionary = corpora.Dictionary(contents_clean)
corpus = [dictionary.doc2bow(sentence) for sentence in contents_clean]
# 建模
lda = gensim.models.ldamodel.LdaModel(corpus=corpus, id2word=dictionary, num_topics=20) #类似Kmeans自己指定K值
查看主题词提取结果
for topic in lda.print_topics(num_topics=20, num_words=5):
print (topic[1])
0.005*"万" + 0.004*"号" + 0.003*"热血" + 0.003*"同学" + 0.003*"防守"
0.023*"a" + 0.022*"e" + 0.016*"i" + 0.016*"o" + 0.015*"n"
0.006*"老公" + 0.005*"饰演" + 0.005*"说" + 0.005*"两人" + 0.004*"中"
0.008*"中" + 0.008*"男人" + 0.006*"女人" + 0.005*"说" + 0.003*"D"
0.012*"电影" + 0.011*"导演" + 0.008*"中" + 0.005*"影片" + 0.005*"主演"
0.006*"中" + 0.005*"西班牙" + 0.003*"航母" + 0.003*"葡萄牙" + 0.003*"前锋"
0.006*"比赛" + 0.006*"中" + 0.006*"皮肤" + 0.003*"含有" + 0.003*"蛋白质"
0.010*"说" + 0.007*"中" + 0.007*"中国" + 0.004*"学校" + 0.003*"舞台"
0.007*"中" + 0.004*"说" + 0.004*"吃" + 0.004*"食物" + 0.003*"M"
0.007*"M" + 0.007*"L" + 0.007*"S" + 0.004*"T" + 0.004*"G"
0.009*"官兵" + 0.005*"部队" + 0.004*"武警" + 0.004*"说" + 0.004*"工作"
0.020*"男人" + 0.008*"女人" + 0.008*"该剧" + 0.006*"剧中" + 0.006*"剧"
0.008*"万" + 0.007*"号" + 0.005*"转" + 0.003*"V" + 0.003*"e"
0.010*"球队" + 0.010*"比赛" + 0.009*"选手" + 0.008*"中" + 0.007*"中国"
0.029*"节目" + 0.013*"主持人" + 0.012*"卫视" + 0.007*"粉丝" + 0.007*"主持"
0.006*"中" + 0.005*"中国" + 0.004*"万" + 0.003*"市场" + 0.003*"公司"
0.008*"中" + 0.005*"恋情" + 0.004*"分手" + 0.004*"说" + 0.004*"学生"
0.005*"观众" + 0.005*"中" + 0.005*"说" + 0.004*"婚礼" + 0.004*"於"
0.005*"S" + 0.004*"I" + 0.004*"中" + 0.003*"e" + 0.003*"女主角"
0.007*"考生" + 0.007*"李小璐" + 0.006*"中" + 0.005*"剧组" + 0.003*"C"
中文新闻分类任务
因为在数据集中,category相当于我们的 label,但它是中文的,需要将其改为数字形式,最后用贝叶斯分类器进行新闻分类操作
# 整合训练数据
df_train=pd.DataFrame({'contents_clean':contents_clean,'label':df_news['category']})
首先拿到 label 表中的标签
df_train.label.unique()
array(['汽车', '财经', '科技', '健康', '体育', '教育', '文化', '军事', '娱乐', '时尚'],
dtype=object)
对标签做映射
# label替换
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)
因为后面将数据转化为向量的需求,我们需要提前将文章转换成 str 格式,转化时需要用 sklearn 的 CountVectorizer
这里先用一个例子看一下 CountVectorizer 是怎么使用的:
- 例1:使用默认 ngram_range=(1, 1) 进行向量化处理
from sklearn.feature_extraction.text import CountVectorizer
# 语料库demo
texts=["dog cat fish","dog cat cat","fish bird", 'bird']
# 实例化
cv = CountVectorizer()
# 构造向量
cv_fit=cv.fit_transform(texts)
# 打印语料库所有不重复单词
print(cv.get_feature_names())
# 打印向量
print(cv_fit.toarray())
# 打印词频统计
print(cv_fit.toarray().sum(axis=0))
['bird', 'cat', 'dog', 'fish']
[[0 1 1 1]
[0 2 1 0]
[1 0 0 1]
[1 0 0 0]]
[2 3 2 2]
- 例2:设置 ngram_range=(1,4) 进行向量化处理
from sklearn.feature_extraction.text import CountVectorizer
# 语料库demo
texts=["dog cat fish","dog cat cat","fish bird", 'bird']
# 实例化
cv = CountVectorizer(ngram_range=(1,4))
# 构造向量
cv_fit=cv.fit_transform(texts)
# 打印语料库所有不重复单词
print(cv.get_feature_names())
# 打印向量
print(cv_fit.toarray())
# 打印词频统计
print(cv_fit.toarray().sum(axis=0))
['bird', 'cat', 'cat cat', 'cat fish', 'dog', 'dog cat', 'dog cat cat', 'dog cat fish', 'fish', 'fish bird']
[[0 1 0 1 1 1 0 1 1 0]
[0 2 1 0 1 1 1 0 0 0]
[1 0 0 0 0 0 0 0 1 1]
[1 0 0 0 0 0 0 0 0 0]]
[2 3 1 1 2 2 1 1 2 1]
例1在做分词向量时,是每个词都分开,但是还有一种方法是对分词进行组合,将向量维度做的更复杂
参数说明:ngram_range = (1, 4) 表示选取1到4个词做为组合方式: 词向量组合为: ‘dog’, ‘cat’, ‘fish’, ‘dog cat’, ‘cat fish’, ‘dog cat fish’ 构成词频标签
通过这两个例子,我们可以看到,语料库的格式是一个 list 结构,每个元素是str结构,并且用逗号隔开,里面的分词以空格方式间隔,所以我们的数据集也要转换成这样一种格式
#转换成 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 逄 煳 幕 传播 迪欧 咖啡 联合 出品 出品人 希望 观摩 扪心自问 父亲节 父亲 记得 父亲 生日 哪一天 父亲 爱喝 跨出 家门 那一刻 感觉 一颗 颤动 心 操劳 天下 儿女 父亲节 大声 喊出 父亲 家人 爱 完'
处理完训练集,再对测试集进行相同的操作
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 构造Ngram词袋模型 与 TfidfVectorizer 构造 tf-idf 词袋模型
CountVectorizer() 函数
CountVectorizer()函数,在默认参数下,只考虑每个单词出现的频率;然后构成一个特征矩阵,每一行表示一个训练文本的词频统计结果(也可以通过 ngram_range 参数调整词组,构建更复杂的矩阵)。其思想是,先根据所有训练文本,不考虑其出现顺序,只将训练文本中每个出现过的词汇单独视为一列特征,构成一个词汇表,该方法又称为词袋法(Bag of Words)
TfidfVectorizer() 函数
TfidfVectorizer() 函数,基于tf-idf算法,计算方法在开头有讲
- 方法1:使用 CountVectorizer 构造Ngram词袋模型
from sklearn.feature_extraction.text import CountVectorizer
# 实例化
vec = CountVectorizer(analyzer='word', max_features=4000, lowercase = False)
# 执行向量转化
vec.fit(words)
进行贝叶斯建模,训练
from sklearn.naive_bayes import MultinomialNB
classifier = MultinomialNB()
classifier.fit(vec.transform(words), y_train)
进行测试
classifier.score(vec.transform(test_words), y_test)
最终贝叶斯分类器的结果是0.804
- 方法2:使用 TfidfVectorizer 构造 tf-idf 词袋模型
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.8152