用 Python 做文本分析 文本分析的本质是从给定文本中获取高质量、有用信息的自动化过程,其一般步骤为:数据采集、数据清洗、文本挖掘分析、可视化分析 。 从非结构化文本中提取特定信息,如:实体、情感分析、关键词、主题、知识管理和发现(按主题对文档进行整理和分类以便于发现,然后向读者推荐与同一主题相关的其他文章,以提供个性化的内容推荐)、聚类… 在公司实际工作中,最好的大数据挖掘工程师一定是最熟悉和理解业务的人。对于大数据挖掘的学习心得,作者认为学习数据挖掘一定要结合实际业务背景、案例背景 来学习,这样才是以解决问题为导向的学习方法。
文本分析的步骤
常见数据挖掘方法
导包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import reimport osimport numpy as npimport codecsfrom time import timefrom tqdm import tqdmimport refrom wordCloud import doWordCloudimport jiebaimport jieba.posseg from jieba.analyse import *from sklearn.feature_extraction.text import TfidfVectorizer, CountVectorizerfrom sklearn.decomposition import LatentDirichletAllocationfrom sklearn.cluster import MiniBatchKMeans, SpectralCoclusteringfrom sklearn.metrics.cluster import v_measure_scoreimport stringfrom zhon.hanzi import punctuationimport gensimimport gensim.corpora as corporafrom snownlp import SnowNLPimport matplotlib.pyplot as pltfrom colorama import init, Fore, Back, Style
数据采集 读入我们的数据文件,显式指定编码类型,以免出现乱码错误
1 2 3 4 for txt_file in tqdm(os.listdir(path)): if not os.path.isdir(txt_file): with codecs.open (path + "/" + txt_file, "r" , "utf-8" ) as f:
数据预处理 数据分析/挖掘领域有一条金科玉律:“Garbage in, Garbage out”,做好数据预处理,对于取得理想的分析结果来说是至关重要的。本文的数据规整主要是对文本数据进行清洗,处理的条目如下:
去除文本噪声信息 处理编码问题 (codecs) 去掉停用词(没有实际意义的符号) 标点符号:, 。! /、*+-
特殊符号:❤❥웃유♋☮✌☏☢☠✔☑♚▲♪等
中文停用词
将文档分割成句子
中文分词 tokenize (jieba, 了避免歧义和切出符合预期效果的词汇,笔者采取的是精确(分词)模式)
词性标注。snownlp 是不二选择,还可以使用 pattern
计算Bigrams:如果两个词经常一起毗邻出现,那么这两个词可以结合成一个新词 (未使用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 stop_words = []with codecs.open (stopWord_path, "r" , "utf-8" ) as f: for line in f: stop_words.append(line.strip("\n" ).strip()) ...with codecs.open (path + "/" + txt_file, "r" , "utf-8" ) as f: file_content = f.read() file_content = re.sub(r"^\s+$" , "" , file_content) file_content = re.sub("[0-9a-zA-Z_-]+" , "" , file_content) file_content = re.sub(r"[%s]+" % punctuation, "" , file_content) file_content = re.sub(r"[%s]+" % string.punctuation, "" , file_content) word_list = jieba.cut(file_content) word_list = [w for w in word_list if w not in stop_words] segments.append(" " .join(word_list))
单词之间都已经被空格区分开了。下面我们需要做一项重要工作,叫做文本的向量化 。
不要被这个名称吓跑。它的意思其实很简单。因为计算机不但不认识中文,甚至连英文也不认识,它只认得数字。我们需要做的,是把文章中的关键词转换为一个个特征(列),然后对每一篇文章数关键词出现个数。
特征抽取 我们希望获取到的词汇,既能保留文本的信息,同时又能反映它们的相对重要性。
特征选取的方式:
构建词向量空间:统计文本词频,生成文本的词向量空间
权重策略——TF-IDF:使用TF-IDF发现特征词,并抽取为反映文档主题的特征
经过上面的步骤之后,我们就可以把文本集转化成一个矩阵。
TF-IDF向量化 1 2 3 4 5 6 7 vectorizer = TfidfVectorizer(stop_words=stop_words, sublinear_tf=True , max_df=0.5 )print ("\nvectorizing..." ) vector = vectorizer.fit_transform(segments)
文本挖掘 关于文本挖掘方面的相关知识,请参看《数据运营|数据分析中,文本分析远比数值型分析重要!(上)》 、《在运营中,为什么文本分析远比数值型分析重要?一个实际案例,五点分析(下)》 。
本文的文本挖掘部分主要涉及:1 2 3 4 5 6 7 8 9 高频词统计/关键词提取/ 关键词云 TF-IDF的关键词提取方法 文章标题聚类 文章内容聚类 文章内容LDA主题模型分析 词向量/关联词分析 ATM模型 词汇分散图 词聚类分析
用Python提取中文关键词
对于关键词提取,笔者没有采取词频统计的方法,因为词频统计的逻辑是:一个词在文章中出现的次数越多,则它就越重要。因而,笔者采用的是TF-IDF(termfrequency–inverse document frequency)的关键词提取方法:
1 2 3 4 5 6 7 8 9 10 11 12 print (Fore.RED + "关键词提取结果如下:" ) topk_list = textrank("\n" .join(segments), withWeight=True , topK=100 ) topk_keyword = []with codecs.open ('result/TextRank算法提取的 TOP100 关键词.txt' , 'w' , 'utf-8' ) as f: for keyword, weight in topk_list: f.write("{}\t{}\n" .format (keyword, weight)) topk_keyword.append(keyword) print (Fore.GREEN + "%s\t%s" % (keyword, weight)) doWordCloud(' ' .join(topk_keyword), stop_words)
下面是笔者利用jieba在经预处理后的、近70MB的语料中抽取出的TOP100关键词(略)
统计性分析 只从文本中提取1000个最重要的特征关键词,然后停止
1 2 3 4 5 6 7 8 9 10 11 12 n_features = 1000 vectorizer = CountVectorizer( max_df=0.95 , min_df=2 , max_features=n_features, strip_accents="unicode" , stop_words=stop_words, ) vector = vectorizer.fit_transform(segments) vocab = vectorizer.vocabulary_ cipin = vector.toarray()
利用LDA进行主题抽取 刚才针对关键词的分类较为粗略,且人为划分,难免有失偏颇,达不到全面的效果。因此,笔者采用LDA主题模型来发现该语料中的潜在主题。关于LDA主题模型的相关原理,请参看《【干货】用大数据文本挖掘,来洞察“共享单车”的行业现状及走势》 的第4部分。
LDA是一种典型的无监督(也就是说,我们事先不知道每段文本里面说的是啥,每个文本没有啥标签)、基于统计学习的词袋模型,即它认为一篇文档是由一组词构成的一个集合,词与词之间没有顺序以及先后的关系。一篇文档可以包含多个主题,文档中每一个词都由其中的一个主题生成。主题模型通过分析文本中的词来发现文档中的主题、主题之间的联系方式和主题的发展,通过主题模型可以使我们组织和总结无法人工标注的海量电子文档。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 def trainLDA (vector ): n_topics = [5 ] perplexityLst = [1.0 ]*len (n_topics) lda_models = [] for idx, n_topic in enumerate (n_topics): lda = LatentDirichletAllocation(n_components=n_topic, max_iter=100 , learning_method='batch' , evaluate_every=200 , learning_offset=50.0 , random_state=0 ) t0 = time() lda.fit(vector) perplexityLst[idx] = lda.perplexity(vector) lda_models.append(lda) print ("# of Topic: %d, " % n_topics[idx]) print ("done in %0.3fs, N_iter %d, " % ((time() - t0), lda.n_iter_)) print ("收敛效果 Perplexity Score (越小越好) %0.3f" % perplexityLst[idx]) best_index = perplexityLst.index(min (perplexityLst)) best_n_topic = n_topics[best_index] best_model = lda_models[best_index] print (Fore.RED + "Best # of Topic: " , best_n_topic) print ('\n' ) def print_top_words (model, feature_names, n_top_words ): with codecs.open ("result/主题簇.txt" , "w" , "utf-8" ) as f: for topic_idx, topic in enumerate (model.components_): f.write("Topic #%d:\n" % topic_idx) f.write( "\n" .join( [feature_names[i] for i in topic.argsort()[: -n_top_words - 1 : -1 ]] ) ) f.write("\n" ) print (Fore.RED + "Topic #%d:" % topic_idx) print ( Fore.GREEN + " " .join( [feature_names[i] for i in topic.argsort()[: -n_top_words - 1 : -1 ]] ) ) print ("\n" ) n_top_words = 10 tf_feature_names = vectorizer.get_feature_names() print_top_words(lda, tf_feature_names, n_top_words) doc_topic_dist = lda.transform(vector) trainLDA(vector)
一般情况下,笔者将主题的数量设定为10个,经过数小时的运行,得到如下结果:
1 2 3 4 5 6 7 8 9 10 Topic 学习 模型 使用 算法 方法 机器 可视化 神经网络 特征 处理 计算 系统 不同 数据库 训练 分类 基于 工具 一种 深度 Topic 这个 就是 可能 如果 他们 没有 自己 很多 什么 不是 但是 这样 因为 一些 时候 现在 用户 所以 非常 已经 Topic 企业 平台 服务 管理 互联网 公司 行业 数据分析 业务 用户 产品 金融 创新 客户 实现 系统 能力 产业 工作 价值 Topic 中国 2016 电子 增长 10 市场 城市 2015 关注 人口 检索 30 或者 其中 阅读 应当 美国 全国 同比 20 Topic 人工智能 学习 领域 智能 机器人 机器 人类 公司 深度 研究 未来 识别 已经 医疗 系统 计算机 目前 语音 百度 方面
利用LDA做了主题抽取,不论是5个还是10个主题,可能都不是最优的数量选择。你可以根据程序反馈的结果不断尝试。
ATM模型 ATM模型(author-topic model)也是“概率主题模型”家族的一员,是LDA主题模型(Latent Dirichlet Allocation )的拓展,它能对某个语料库中作者的写作主题进行分析,找出某个作家的写作主题倾向,以及找到具有同样写作倾向的作家,它是一种新颖的主题探索方式。
词向量/关联词分析 词聚类 文档聚类
每一条评论都围绕一个或几个核心主旨进行阐述,这个核心主旨就是评论的中心思想。基于主旨话题分析技术获取文本主旨,每一条评论可能包含多个主旨话题,每一个话题包含多个主题词,通过评论的隶属度确定评论所属的主旨话题,通过主题词的分布确定主旨的含义。评论话题的具体分析流程如下,此过程要依次进行词法分析、文本过滤、主旨话题分析:
接下来采用的是基于谱联合聚类算法(Spectral Co-clustering algorithm)的文档聚类,这部分的原理涉及到艰深的数学和算法知识,可能会引起小伙伴们的阅读不适感,如果是这样,请快速跳过,直接看后面的操作和结果。
先将待分析的文本经TF-IDF向量化构成了词频矩阵,然后使用Dhillon的谱联合聚类算法(Spectral Co-clustering algorithm)进行双重聚类(Biclusters)。所得到的“文档-词汇”双聚类(Biclusters)会把某些文档子集中的常用词汇聚集在一起,由若干个关键词构成某个主题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 def writeClusterResult (y ): result_dict = {} for i in range (len (y)): if y[i] not in result_dict: result_dict[y[i]] = [] result_dict[y[i]].append(os.listdir(path)[:15 ][i].strip()) result_list = sorted (result_dict.items(), key=lambda d: len (d[1 ]), reverse=True ) with codecs.open ("result/prediction_cluster.txt" , "w" , encoding='utf-8' ) as target: for item in result_list: target.write("{}\n{}\n\n" .format (item[0 ], "\n" .join(item[1 ]))) print ('聚类结果写入文件完成!!!' ) n_clusters = 5 kmeans = MiniBatchKMeans(n_clusters=n_clusters, batch_size=20000 , random_state=0 )print ("MiniBatchKMeans..." ) y_kmeans = kmeans.fit_predict(vector).tolist() y_kmeans = np.array(y_kmeans) writeClusterResult(y_kmeans)
参考 如何用Python从海量文本抽取主题?
如何用Python做词云
如何从 “用户评论”中挖掘业务价值
【干货】用大数据文本挖掘,来洞察“共享单车”的行业现状及走势
以虎嗅网4W+文章的文本挖掘为例,展现数据分析的一整套流程