数据挖掘1 - 文本分析
词频统计 - 语料库的构建
遍历路径下的所有文件和子目录
os.walk()
读取目录及其所有子目录
- root —— str,表示当前所读到的目录的路径
- dirs —— list,表示该路径下的所有子目录名
- files —— list,表示该路径下的所有文件名
os.path.join(root, name)
解决不同系统下的路径拼接
import os
import os.path
filePaths = []
for root, dirs, files in os.walk(
"SogouC.mini\\Sample"
):
for name in files:
filePaths.append(os.path.join(root, name))
读取文件的内容
codecs.open(filePath, mode, 'utf-8')
用于打开一个文件
参数 | 注释 |
---|---|
filePath | 文件路径 |
mode | 打开方式,有:'r'只读 |
encoding | 文件的编码方式 |
f.read()
读取所有字符内容
import codecs
filePaths = [];
fileContents = [];
for root, dirs, files in os.walk(
"SogouC.mini\\Sample"
):
for name in files:
filePath = os.path.join(root, name);
filePaths.append(filePath);
f = codecs.open(filePath, 'r', 'utf-8')
fileContent = f.read()
f.close()
fileContents.append(fileContent)
import pandas;
corpos = pandas.DataFrame({
'filePath': filePaths,
'fileContent': fileContents
})
作业:把文件的分类,作为语料库数据框的新的一列,加入到语料库中
from pandas import read_table
# 读取 ClassList.txt 并生成 dataFrame
df = read_table(
'SogouC.mini/ClassList.txt',
names=['dirName', 'category'],
sep=' ',
encoding='UTF-8',
engine='python'
)
import os
import os.path
import codecs
# 读取所有文件路径、文件内容、所在目录的文件名并各自保存在 list
filePaths = [];
fileContents = [];
dirNames = [];
for root, dirs, files in os.walk(
"SogouC.mini\\Sample"
):
a = root.split('\\')
for name in files:
filePath = os.path.join(root, name);
filePaths.append(filePath);
dirNames.append(a[len(a) - 1]);
f = codecs.open(filePath, 'r', 'utf-8')
fileContent = f.read()
f.close()
fileContents.append(fileContent)
import pandas
# 将所有文件路径、文件内容、所在目录的文件名生成 dataFrame
corpos = pandas.DataFrame({
'filePath': filePaths,
'fileContent': fileContents,
'dirName': dirNames
})
# 使用字段匹配将两个 dataFrame 合为一个
newDF = pandas.merge(
df,
corpos,
left_on='dirName',
right_on='dirName'
)
词频统计 - 中文分词
模块 jieba
的使用
jieba.cut()
对 str 进行分词,返回一个 generator
import jieba
for w in jieba.cut("我爱Python"):
print(w)
for w in jieba.cut("""
工信处女干事
每月经过下属科室都要亲口交代
24口交换机等技术性器件的安装工作
"""):
print(w)
jieba.add_word()
当有一些专有名字分词效果不好或不希望被分词,可用于添加
jieba.add_word('真武七截阵')
jieba.add_word('天罡北斗阵')
seg_list = jieba.cut(
"真武七截阵和天罡北斗阵哪个更厉害呢?"
)
for w in seg_list:
print(w)
jieba.load_userdict()
用于添加专业的词典
jieba.load_userdict(
'金庸武功招式.txt'
)
综合文件读取和分词例子:
import os;
import os.path;
import codecs;
filePaths = [];
fileContents = [];
for root, dirs, files in os.walk(
"SogouC.mini\\Sample"
):
for name in files:
filePath = os.path.join(root, name);
filePaths.append(filePath);
f = codecs.open(filePath, 'r', 'utf-8')
fileContent = f.read()
f.close()
fileContents.append(fileContent)
import pandas;
corpos = pandas.DataFrame({
'filePath': filePaths,
'fileContent': fileContents
});
import jieba
segments = []
filePaths = []
for index, row in corpos.iterrows():
filePath = row['filePath']
fileContent = row['fileContent']
segs = jieba.cut(fileContent)
for seg in segs:
segments.append(seg)
filePaths.append(filePath)
segmentDataFrame = pandas.DataFrame({
'segment': segments,
'filePath': filePaths
});
词频统计 - 实现
数据准备:
import os;
import os.path;
import codecs;
filePaths = [];
fileContents = [];
for root, dirs, files in os.walk(
"SogouC.mini\\Sample"
):
for name in files:
filePath = os.path.join(root, name);
filePaths.append(filePath);
f = codecs.open(filePath, 'r', 'utf-8')
fileContent = f.read()
f.close()
fileContents.append(fileContent)
import pandas;
corpos = pandas.DataFrame({
'filePath': filePaths,
'fileContent': fileContents
});
import jieba
segments = []
filePaths = []
for index, row in corpos.iterrows():
filePath = row['filePath']
fileContent = row['fileContent']
segs = jieba.cut(fileContent)
for seg in segs:
segments.append(seg)
filePaths.append(filePath)
segmentDataFrame = pandas.DataFrame({
'segment': segments,
'filePath': filePaths
});
dataFrame.groupby
用于进行分组,并统计出现的次数
dataFrame.sort_values()
第一个参数为要依据排序的字段,ascending 表示是否按找升序排序
import numpy
# 进行词频统计
# 并对统计后的根据出现的次数排序
segStat = segmentDataFrame.groupby(
by="segment"
)["segment"].agg({
"计数":numpy.size
}).reset_index().sort_values(
"计数",
ascending=False
);
移除停用词的两种方式:
-
对统计结果进行剔除
列表包含:
dataFrame.列名.isin(series)
取反:
df[~df.列名.isin(series)]
stopwords = pandas.read_csv( "StopwordsCN.txt", encoding='utf8', index_col=False ) fSegStat = segStat[ ~segStat.segment.isin(stopwords.stopword) ]
-
在分词的时候就处理掉
import jieba segments = [] filePaths = [] for index, row in corpos.iterrows(): filePath = row['filePath'] fileContent = row['fileContent'] segs = jieba.cut(fileContent) for seg in segs: if seg not in stopwords.stopword.values and len(seg.strip())>0: segments.append(seg) filePaths.append(filePath) segmentDataFrame = pandas.DataFrame({ 'segment': segments, 'filePath': filePaths }); segStat = segmentDataFrame.groupby( by="segment" )["segment"].agg({ "计数":numpy.size }).reset_index().sort( columns=["计数"], ascending=False );
词云绘制
wordcloud
包用于绘制词云
WordCloud(font_path, background_color)
新建一个 WordCloud 实例,参数是 字体的地址 和 背景色
wordcloud.fit_words(dict)
填词,接受一个 dict ,以词为 key ,次数为 value
dataFrame.set_index('keyIndex').to_dict()
将一个 dataFrame 以 'keyIndex' 对应的列为 key ,以其他列为 value ,生成多个 dict 保存在一个 dict 里,该 dict 以其他列的列名为 key
from wordcloud import WordCloud
import matplotlib.pyplot as plt
wordcloud = WordCloud(
font_path='simhei.ttf',
background_color="black"
)
words = fSegStat.set_index('segment').to_dict()
wordcloud.fit_words(words['计数'])
plt.imshow(wordcloud)
plt.close()
词云美化
数据准备:
import jieba
import numpy
import codecs
import pandas
file = codecs.open(
"红楼梦.txt", 'r', 'utf-8'
)
content = file.read()
file.close()
jieba.load_userdict('红楼梦词库.txt');
segments = []
segs = jieba.cut(content)
for seg in segs:
if len(seg)>1:
segments.append(seg);
segmentDF = pandas.DataFrame({'segment':segments})
#移除停用词
stopwords = pandas.read_csv(
"StopwordsCN.txt",
encoding='utf8',
index_col=False,
quoting=3,
sep="\t"
)
segmentDF = segmentDF[
~segmentDF.segment.isin(stopwords.stopword)
]
wyStopWords = pandas.Series([
# 42 个文言虚词
'之', '其', '或', '亦', '方', '于', '即', '皆', '因', '仍', '故',
'尚', '呢', '了', '的', '着', '一', '不', '乃', '呀', '吗', '咧',
'啊', '把', '让', '向', '往', '是', '在', '越', '再', '更', '比',
'很', '偏', '别', '好', '可', '便', '就', '但', '儿',
# 高频副词
'又', '也', '都', '要',
# 高频代词
'这', '那', '你', '我', '他',
#高频动词
'来', '去', '道', '笑', '说',
#空格
' ', ''
]);
segmentDF = segmentDF[
~segmentDF.segment.isin(wyStopWords)
]
segStat = segmentDF.groupby(
by=["segment"]
)["segment"].agg({
"计数":numpy.size
}).reset_index().sort_values(
"计数",
ascending=False
);
imread()
读取图片
WordCloud(...,mask,...)
mask 图像的区域为显示的区域
ImageColorGenerator()
根据图片对象获取图片颜色
wordcloud.recolor(color_func)
根据 color_func 返回一个 wordcloud 对象,即重置词云的颜色
from scipy.misc import imread
import matplotlib.pyplot as plt
from wordcloud import WordCloud, ImageColorGenerator
bimg = imread("贾宝玉2.png")
wordcloud = WordCloud(
font_path='simhei.ttf',
background_color="white",
mask=bimg
)
wordcloud = wordcloud.fit_words(words['计数'])
plt.figure(
num=None,
figsize=(16, 12),
dpi=80,
facecolor='w',
edgecolor='k'
)
bimgColors = ImageColorGenerator(bimg)
plt.axis("off")
plt.imshow(wordcloud.recolor(color_func=bimgColors))
plt.show()
关键词提取
jieba.analyse.extract_tags(content, topK=5)
提取关键词,content 为待提取内容,topK 表示提取多少个关键词,返回一个 list
import os
import codecs
import pandas
import jieba
import jieba.analyse
filePaths = []
contents = []
tag1s = []
tag2s = []
tag3s = []
tag4s = []
tag5s = []
for root, dirs, files in os.walk(
"SogouC.mini\\Sample\\"
):
for name in files:
filePath = root + '\\' + name;
f = codecs.open(filePath, 'r', 'utf-8')
content = f.read().strip()
f.close()
tags = jieba.analyse.extract_tags(content, topK=5)
filePaths.append(filePath)
contents.append(content)
tag1s.append(tags[0])
tag2s.append(tags[1])
tag3s.append(tags[2])
tag4s.append(tags[3])
tag5s.append(tags[4])
tagDF = pandas.DataFrame({
'filePath': filePaths,
'content': contents,
'tag1': tag1s,
'tag2': tag2s,
'tag3': tag3s,
'tag4': tag4s,
'tag5': tag5s
})
关键词提取的实现
-
TF-IDF 原理
词频( TF, Term Frequency ) 词在该文档中出现的次数
逆文档频率( IDF, Inverse Document Frequency ) 词的权重,大小与词的常见程度成反比
TF-IDF( Term Frequency - Inverse Document Frequency ) 权衡分词是否关键词的指标,值越大越可能TF 计算公式:TF = 词在文档中出现的次数
IDF 计算公式:IDF = log( 文档总数 / ( 包含该词的文档数 + 1 ) )
TF - IDF 计算公式:TF-IDF = TF * IDF
文档向量化 dataFrame.pivot_table()
dataFrame.apply(funcName)
接收一个函数,该函数参数为 series,函数返回一个数,dataFrame 将每一列作为参数依次调用该函数做处理,最后返回一个 Series,以 dataFrame 的字段名为索引,对应函数返回的值为 values
dataFrame * series
dataFrame 与 series 的乘积类似矩阵的运算,dataFrame 的每一行乘以 series,相同位置的数据进行运算,结果保留在相同位置
series.sort_values(ascending=False)
根据值对 series 进行排序
import numpy
#创建语料库
import os;
import os.path;
import codecs;
filePaths = [];
fileContents = [];
for root, dirs, files in os.walk(
"SogouC.mini\\Sample"
):
for name in files:
filePath = os.path.join(root, name);
filePaths.append(filePath);
f = codecs.open(filePath, 'r', 'utf-8')
fileContent = f.read()
f.close()
fileContents.append(fileContent)
import pandas;
corpos = pandas.DataFrame({
'filePath': filePaths,
'fileContent': fileContents
});
import re
#匹配中文的分词
# 正则匹配,u'[\u4e00-\u9fa5]+' 表示至少有一个中文
zhPattern = re.compile(u'[\u4e00-\u9fa5]+')
import jieba
segments = []
filePaths = []
for index, row in corpos.iterrows():
filePath = row['filePath']
fileContent = row['fileContent']
segs = jieba.cut(fileContent)
for seg in segs:
if zhPattern.search(seg):
segments.append(seg)
filePaths.append(filePath)
segmentDF = pandas.DataFrame({
'filePath':filePaths,
'segment':segments
})
#移除停用词
stopwords = pandas.read_csv(
"StopwordsCN.txt",
encoding='utf8',
index_col=False,
quoting=3,
sep="\t"
)
segmentDF = segmentDF[
~segmentDF.segment.isin(stopwords.stopword)
]
#按文章进行词频统计
segStat = segmentDF.groupby(
by=["filePath", "segment"]
)["segment"].agg({
"计数":numpy.size
}).reset_index().sort_values(
"计数",
ascending=False
);
# 把小部分的数据删除掉
# 只保留频次大于一的中文
segStat = segStat[segStat.计数>1]
# 进行文本向量计算
# 交叉统计,以文件路径(表示文件)为行,以分词为列,以频数为值
TF = segStat.pivot_table(
index='filePath',
columns='segment',
values='计数',
fill_value=0
)
TF.index
TF.columns
# 计算 IDF
def hanlder(x):
return (numpy.log2(len(corpos)/(numpy.sum(x>0)+1)))
IDF = TF.apply(hanlder)
TF_IDF = pandas.DataFrame(TF*IDF)
tag1s = []
tag2s = []
tag3s = []
tag4s = []
tag5s = []
for filePath in TF_IDF.index:
tagis = TF_IDF.loc[filePath].sort_values(
ascending=False
)[:5].index
tag1s.append(tagis[0])
tag2s.append(tagis[1])
tag3s.append(tagis[2])
tag4s.append(tagis[3])
tag5s.append(tagis[4])
tagDF = pandas.DataFrame({
'filePath':corpos.filePath,
'fileContent':corpos.fileContent,
'tag1':tag1s,
'tag2':tag2s,
'tag3':tag3s,
'tag4':tag4s,
'tag5':tag5s
})
使用 sklearn 包
使用 sklearn 包进行 TF-IDF 计算\
countVectorizer = CountVectorizer()
新建一个 CountVectorizer 实例,可设置 min_df
—— 分词的最小长度,token_pattern
—— 分词的正则表达式,stop_words
接受一个 list ,表示要排除的分词
countVectorizer.fit_transform(contents)
contents 为 list,对 list 的每一个 str 进行分词,返回一个文档向量化的矩阵
countVectorizer.fit_transform(series)
countVectorizer.vocabulary_
得到一个 dict ,查看文档向量化的矩阵每一列对应是什么分词及其对应索引
countVectorizer.get_feature_names()
得到一个 list ,得到所有的分词
textVector.todense()
查看该文档向量化的矩阵,对应分词出现一个值为1,两次值为2
transformer = TfidfTransformer()
新建一个 TfidfTransformer 实例,用于计算 tf-idf
tfidf = transformer.fit_transform(textVector)
根据得到的文档向量化的矩阵计算得到 tf-idf,结构与 textVector 相同
tfidf.toarray()
得到一个 array,以行为一个 list ,得到 list 的集合 list
DataFrame(array)
根据 array 新建一个 DataFrame,索引和字段名都是从0开始
numpy.argsort(tfidf.toarray(), axis=1)
对一个 array(二维 list)排序,axis=1 指行排序,默认升序排序,返回对应的index
array.[:, -2:]
截取每行倒数两个元素
dataFrame.columns[array]
获取指定位置序号下的 column,从新组成一个 array
dataFrame.columns[array].values
contents = [
'我 是 中国 人。',
'你 是 美国 人。',
'他 叫 什么 名字?',
'她 是 谁 啊?'
];
from sklearn.feature_extraction.text import CountVectorizer
# 分词
# 默认为忽略单字
countVectorizer = CountVectorizer()
# 得到一个文档向量化的矩阵
textVector = countVectorizer.fit_transform(contents);
# 获取该矩阵
textVector.todense()
# 查看每一列对应是什么分词即其对应索引
countVectorizer.vocabulary_
countVectorizer = CountVectorizer(
# 最小长度
min_df=0,
# 分词的正则表达式
token_pattern=r"\b\w+\b"
)
textVector = countVectorizer.fit_transform(contents);
textVector.todense()
countVectorizer.vocabulary_
from sklearn.feature_extraction.text import TfidfTransformer
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(textVector)
tfidf.todense()
countVectorizer.vocabulary_
import pandas;
# 矩阵.toarray() 以行为一个 list ,得到 list 的集合 list
TFIDFDataFrame = pandas.DataFrame(tfidf.toarray());
# countVectorizer.get_feature_names() 获取分词的 list
TFIDFDataFrame.columns = countVectorizer.get_feature_names();
import numpy;
# numpy.argsort() 是对矩阵的元素值排序后返回序列矩阵,第一个参数接收一个二维数组,axis=0 按列排序,axis=1 按行排序。[:, -2:] 表示对二维数组最外层的 list 不变,里层的数组切片获取后两个
TFIDFSorted = numpy.argsort(tfidf.toarray(), axis=1)[:, -2:]
TFIDFDataFrame.columns[TFIDFSorted].values
str.join(list)
list 转换为 str,元素与元素之间以 str 间隔
series.values
得到一个 array 类型的实例
list(array)
得到一个 list
import os;
import os.path;
import codecs;
filePaths = [];
fileContents = [];
for root, dirs, files in os.walk(
"SogouC.mini\\Sample"
):
for name in files:
filePath = os.path.join(root, name);
filePaths.append(filePath);
f = codecs.open(filePath, 'r', 'utf-8')
fileContent = f.read()
f.close()
fileContents.append(fileContent)
import pandas;
corpos = pandas.DataFrame({
'filePath': filePaths,
'fileContent': fileContents
});
import re
zhPattern = re.compile(u'[\u4e00-\u9fa5]+')
import jieba
segments = []
filePaths = []
for index, row in corpos.iterrows():
segments = []
filePath = row['filePath']
fileContent = row['fileContent']
segs = jieba.cut(fileContent)
for seg in segs:
if zhPattern.search(seg):
segments.append(seg)
filePaths.append(filePath)
row['fileContent'] = " ".join(segments);
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
stopwords = pandas.read_csv(
"StopwordsCN.txt",
encoding='utf8',
index_col=False,
quoting=3,
sep="\t"
)
countVectorizer = CountVectorizer(
stop_words=list(stopwords['stopword'].values),
min_df=0, token_pattern=r"\b\w+\b"
)
textVector = countVectorizer.fit_transform(
corpos['fileContent']
)
transformer = TfidfTransformer()
tfidf = transformer.fit_transform(textVector)
import numpy;
# 矩阵
sort = numpy.argsort(tfidf.toarray(), axis=1)[:, -5:]
# list
names = countVectorizer.get_feature_names();
# pandas.Index(names) 返回一个 series,相当于 list 2 series
# sort 是一个二维数组,pandas.Index(names)[sort] 指获取sort指定索引下的值组成一个二维数组
# pandas.Index(names)[sort].values 将其变为一个 array
keywords = pandas.Index(names)[sort].values
tagDF = pandas.DataFrame({
'filePath':corpos.filePath,
'fileContent':corpos.fileContent,
'tag1':keywords[:, 0],
'tag2':keywords[:, 1],
'tag3':keywords[:, 2],
'tag4':keywords[:, 3],
'tag5':keywords[:, 4]
})
相似文章推荐
推荐包括:相似推荐、协同过滤推荐
相似推荐主要原理:余弦相似度
余弦距离计算:sklearn.metrics.pairwise_distance(textVector, metric="cosine")
matrix: 矩阵;metric="cosine" 距离计算公式。越相似的文章值越小
pandas.DataFrame(matrix)
得到一个 DataFrame
文章的余弦相似度:
- 分词
- 生成语料库
- 向量化(统计词频)
- 计算余弦相似度
import os;
import numpy;
import os.path;
import codecs;
filePaths = [];
fileContents = [];
for root, dirs, files in os.walk(
"SogouC.mini\\Sample"
):
for name in files:
filePath = os.path.join(root, name);
filePaths.append(filePath);
f = codecs.open(filePath, 'r', 'utf-8')
fileContent = f.read()
f.close()
fileContents.append(fileContent)
import pandas;
corpos = pandas.DataFrame({
'filePath': filePaths,
'fileContent': fileContents
});
import re
#匹配中文的分词
zhPattern = re.compile(u'[\u4e00-\u9fa5]+')
import jieba
segments = []
filePaths = []
for index, row in corpos.iterrows():
segments = []
filePath = row['filePath']
fileContent = row['fileContent']
segs = jieba.cut(fileContent)
for seg in segs:
if zhPattern.search(seg):
segments.append(seg)
filePaths.append(filePath)
row['fileContent'] = " ".join(segments);
from sklearn.feature_extraction.text import CountVectorizer
stopwords = pandas.read_csv(
"StopwordsCN.txt",
encoding='utf8',
index_col=False,
quoting=3,
sep="\t"
)
countVectorizer = CountVectorizer(
stop_words=list(stopwords['stopword'].values),
min_df=0, token_pattern=r"\b\w+\b"
)
textVector = countVectorizer.fit_transform(
corpos['fileContent']
)
textVector.todense()
countVectorizer.vocabulary_
from sklearn.metrics import pairwise_distances
distance_matrix = pairwise_distances(
textVector,
metric="cosine"
)
m = 1- pandas.DataFrame(distance_matrix)
m.columns = filePaths;
m.index = filePaths;
# 按行进行排序,取第一列到第五列
sort = numpy.argsort(distance_matrix, axis=1)[:, 1:6]
similarity5 = pandas.Index(filePaths)[sort].values
similarityDF = pandas.DataFrame({
'filePath':corpos.filePath,
's1': similarity5[:, 0],
's2': similarity5[:, 1],
's3': similarity5[:, 2],
's4': similarity5[:, 3],
's5': similarity5[:, 4]
})
自动摘要
算法原理:余弦定理
算法步骤:
- 获取到需要摘要的文章
- 对该文章进行词频统计
- 对该文章进行分句(根据中文的标点符号,一般采用 , 。 ? 等进行分句)
- 计算分句与文章之间的余弦相似度
- 取相似度最高的分句,作为文章的摘要
# -*- coding: utf-8 -*-
import re
import os
import jieba
import codecs
import numpy
import pandas
import os.path
from sklearn.metrics import pairwise_distances
from sklearn.feature_extraction.text import CountVectorizer
filePaths = [];
fileContents = [];
for root, dirs, files in os.walk(
"SogouC.mini\\Sample"
):
for name in files:
filePath = os.path.join(root, name);
filePaths.append(filePath);
f = codecs.open(filePath, 'r', 'utf-8')
fileContent = f.read()
f.close()
fileContents.append(fileContent)
corpos = pandas.DataFrame({
'filePath': filePaths,
'fileContent': fileContents
});
stopwords = pandas.read_csv(
"StopwordsCN.txt",
encoding='utf8',
index_col=False,
quoting=3,
sep="\t"
)
countVectorizer = CountVectorizer(
stop_words=list(stopwords['stopword'].values),
min_df=0,
token_pattern=r"\b\w+\b"
)
contents = []
summarys = []
filePaths = []
# 遍历每一篇文章
for index, row in corpos.iterrows():
filePath = row['filePath']
fileContent = row['fileContent']
#建立子语料库,以该文档和该文档的分句组成
subCorpos = [fileContent] + re.split(
r'[。?!\n]\s*',
fileContent
)
segments = []
suitCorpos = []
for content in subCorpos:
segs = jieba.cut(content)
segment = " ".join(segs)
if len(segment.strip())>10:
segments.append(segment)
suitCorpos.append(content)
textVector = countVectorizer.fit_transform(segments)
# 得到文章+段落 与 文章+段落 之间的余弦距离
distance_matrix = pairwise_distances(
textVector,
metric="cosine"
)
# 得到排序后的编号
sort = numpy.argsort(distance_matrix, axis=1)
# sort[0] 表示全文与段落之间的余弦距离
# values[1] 是因为 values[0] 为文章本身
summary = pandas.Index(suitCorpos)[sort[0]].values[1]
summarys.append(summary)
filePaths.append(filePath)
contents.append(fileContent)
summaryDF = pandas.DataFrame({
'filePath': filePaths,
'content': contents,
'summary': summarys
})
print(summaryDF[99:])