总的来讲,二个全体的文书分类器首要由多个阶段,或然说三个部分组成:一是将文件向量化,将八个字符串转化成向量方式;二是价值观的分类器,包含线性分类器,SVM,
神经网络分类器等等。

http://blog.csdn.net/a\_step\_further/article/details/51176959

事先看的THUCTC的技术栈是使用 tf-idf
来实行文本向量化,使用卡方校验(chi-square)来下落向量维度,使用liblinear(选择线性核的svm)
来开展分类。而这边所述的文件分类器,使用lsi (latent semantic analysis,
隐性语义分析) 来拓展向量化, 不须求降维, 因为能够直接钦命维度,
然后接纳线性核svm实行分拣。lsi的部分珍视采纳gensim来开展,
分类首要由sklearn来实现。具体完成可知行使gensim和sklearn搭建一个文本分类器(二):代码和注释那边首要描述流程

LDA是文本挖掘中常用的大旨模型,用来从大量文书档案中领到出最能发挥各类核心的一些重中之重词,具体算法原理可参看KM上相关小说。作者因作业供给,需对腾讯博客园上多少账号的音信进行主旨提取,故而尝试了一下该算法,基于python的gensim包达成一个简单的分析。

1. 文书档案向量化

那有的的始末根本由gensim来形成。gensim库的部分大旨用法在本身事先的文章中一度有过介绍点这里此地就不再详述,
直接依据流程来写了。选择lsi进行向量化的流程首要有上边几步:

将各文书档案分词,从字符串转化为单词列表

总计各文书档案单词,生成词典(dictionary)

行使词典将文书档案转化成词频表示的向量,即指向量中的各值对应于词典中对应地点单词在该文书档案中出现次数

再展开更进一步处理,将词频表示的向量转化成tf-idf表示的向量

由tf-idf表示的向量转化成lsi表示的向量

接下去依照上述流程来分别解说

安不忘忧工作

  • 安装python的汉语分词模块, jieba
  • 安装python的公文大旨建立模型的模块, gensim (官网
    https://radimrehurek.com/gensim/)。
    这么些模块安装时依赖了一大堆别的包,须要耐心地3个三个设置。

  • 到网络上下载粤语停用词表

1.1 文书档案分词及预处理

分词有很多样方式,也有多如牛毛现成的库,那里仅介绍结巴的简约用法

import jieba

content
=”””面对当前挑战,我们应该完毕2030年可持续发展议程,促进包容性发展”””

content = list(jieba.cut(content, cut_all=False))

print(content)

>>>[‘面对’,’当前’,’挑战’,’,’,’我们’,’应该’,’落实’,’2030′,’年’,’可’,’持续’,’发展’,’议程’,’,’,’促进’,’包容性’,’发展’]

在意下面的cut_all选项,如果cut_all=False, 则会列出最优的剪切选项;
假使cut_all=True, 则会列出装有或者现身的词

content =list(jieba.cut(content, cut_all=True))

print(content)

>>>[‘面对’,’当前’,’挑战’,”,”,’我们’,’应该’,’落实’,’2030′,’年’,’可’,’持续’,’发展’,’议程’,”,”,’促进’,’包容’,’包容性’,’容性’,’发展’]

应该观看到,在分词后的一向结果中,有大气的无用项,例如空格,逗号等等。因而,一般在分词未来,还要开始展览预处理。例如去掉停用词(stop
words, 指的是没什么意思的词,例如空格,逗号,句号,啊,呀, 等等),
去掉现身出现频率过低和过高的词等等。

本身这一局地的先后是

def convert_doc_to_wordlist(str_doc,cut_all):

# 分词的重点方法

sent_list = str_doc.split(‘\n’)

sent_list = map(rm_char, sent_list) # 去掉一部分字符,例如\u3000

word_2dlist = [rm_tokens(jieba.cut(part,cut_all=cut_all)) for
part in sent_list] # 分词

word_list = sum(word_2dlist,[])

return word_list

def rm_char(text):

text = re.sub(‘\u3000’,”,text)

return text

def
get_stop_words(path=’/home/multiangle/coding/python/PyNLP/static/stop_words.txt’):

# stop_words中,每行放3个停用词,以\n分隔

file = open(path,’rb’).read().decode(‘utf8’).split(‘\n’)

return set(file)

def rm_tokens(words): # 去掉一部分停用次和数字

words_list = list(words)

stop_words = get_stop_words()

for i in range(words_list.__len__())[::-1]:

if words_list[i] in stop_words: # 去除停用词

words_list.pop(i)

elif words_list[i].isdigit():

words_list.pop(i)

return words_list

主程序是convert_doc_to_wordlist方法,获得要分词的公文未来,首先去掉一部分字符,例如\u三千等等。然后实行分词,再去掉个中的停用词和数字。
最终获得的单词,其顺序是乱糟糟的,即单词间的连带讯息已经不翼而飞

上代码

[python]

  1. #!/usr/bin/python  
  2. #coding:utf-8  
  3. import sys  
  4. reload(sys)  
  5. sys.setdefaultencoding(“utf8”)  
  6. import jieba  
  7. from gensim import corpora, models  
  8.   
  9.   
  10. def get_stop_words_set(file_name):  
  11.     with open(file_name,’r’) as file:  
  12.         return set([line.strip() for line in file])  
  13.   
  14. def get_words_list(file_name,stop_word_file):  
  15.     stop_words_set = get_stop_words_set(stop_word_file)  
  16.     print “共计导入 %d 个停用词” % len(stop_words_set)  
  17.     word_list = []  
  18.     with open(file_亚洲必赢官网,name,’r’) as file:  
  19.         for line in file:  
  20.             tmp_list = list(jieba.cut(line.strip(),cut_all=False))  
  21.             word_list.append([term for term in tmp_list if str(term) not in stop_words_set]) #注意那里term是unicode类型,借使不转成str,判断会为假  
  22.     return word_list  
  23.   
  24.   
  25. if __name__ == ‘__main__’:  
  26.     if len(sys.argv) < 3:  
  27.         print “Usage: %s <raw_msg_file> <stop_word_file>” % sys.argv[0]  
  28.         sys.exit(1)  
  29.   
  30.     raw_msg_file = sys.argv[1]  
  31.     stop_word_file = sys.argv[2]  
  32.     word_list = get_words_list(raw_msg_file,stop_word_file) #列表,个中每一种成分也是1个列表,即每行文字分词后形成的辞藻列表  
  33.     word_dict = corpora.Dictionary(word_list)  #转移文书档案的词典,每种词与一个整型索引值对应  
  34.     corpus_list = [word_dict.doc2bow(text) for text in word_list] #词频总计,转化成空间向量格式  
  35.     lda = models.ldamodel.LdaModel(corpus=corpus_list,id2word=word_dict,num_topics=10,alpha=’auto’)  
  36.   
  37.     output_file = ‘./lda_output.txt’  
  38.     with open(output_file,’w’) as f:  
  39.         for pattern in lda.show_topics():  
  40.             print >> f, “%s” % str(pattern) 

除此以外还有局部读书资料:https://yq.aliyun.com/articles/26029
[python] LDA处理文书档案主旨分布代码入门笔记

1.2 总括单词,生成词典

一般来讲,
生成词典应该在将持有文书档案都分完词今后统一举办,可是对于规模尤其大的多少,能够采取边分词边总结的不二法门。将文件分批读取分词,然后用事先生成的词典参与新内容的总计结果,如下边所示

from gensim import corpora,models

import jieba

import re

from pprint import pprint

import os

files = [“但是未来教育局非要治理这么三个景色”,

“然则又不搞精晓怎么那个词会现出”]

dictionary = corpora.Dictionary()

for file in files:

file = convert_doc_to_wordlist(file, cut_all=True)

dictionary.add_documents([file])

pprint(sorted(list(dictionary.items()),key=lambda x:x[0]))

>>>[(0, ‘教育’),

>>> (1, ‘治理’),

>>> (2, ‘教育局’),

>>> (3, ‘情况’),

>>> (4, ‘非要’),

>>> (5, ‘搞’),

>>> (6, ‘明白’),

>>> (7, ‘词’)]

对于曾经存在的词典,能够应用dictionary.add_documents来往中间扩展新的内容。当生成词典以后,会发现词典中的词太多了,达到了几80000的数额级,
因而要求去掉出现次数过少的单词,因为那一个代词没怎么代表性。

small_freq_ids = [tokenid for tokenid,
docfreqindictionary.dfs.items() if docfreq <5]

dictionary.filter_tokens(small_freq_ids)

dictionary.compactify()

1.3 将文书档案转化成按词频表示的向量

后续本着从前的思绪走,接下去要用dictionary把文书档案从词语列表转化成用词频表示的向量,约等于one-hot表示的向量。所谓one-hot,正是向量中的一维对应于词典中的一项。要是以词频表示,则向量中该维的值即为词典中该单词在文书档案中冒出的作用。其实那些转化很粗大略,使用dictionray.doc2bow形式即可。

count = 0

bow  = []

for file in files:

count += 1

if count%100 == 0 :

print(‘{c} at {t}’.format(c=count, t=time.strftime(‘%Y-%m-%d
%H:%M:%S’,time.localtime())))

word_list = convert_doc_to_wordlist(file, cut_all=False)

word_bow = dictionary.doc2bow(word_list)

bow.append(word_bow)

pprint(bow)

>>>[[(1, 1), (2, 1), (4, 1)], [(5, 1), (6, 1)]]

1.4 转化成tf-idf和lsi向量

故此把那两有的放到一起,并不是因为那三头的测算办法或许说原理有多相似(实际上两者完全两样),而是说在gensim中总计那二者的调用方法相比接近,都亟待调用gensim.models库。

tfidf_model = models.TfidfModel(corpus=corpus,                         
      dictionary=dictionary)corpus_tfidf =
[tfidf_model[doc]fordocincorpus]lsi_model = models.LsiModel(corpus
= corpus_tfidf,                            id2word = dictionary,       
                    num_topics=50)corpus_lsi =
[lsi_model[doc]fordocincorpus]

1

2

3

4

5

6

7

能够看看gensim的方法照旧相比精简的。

1.5 实践中的一些标题

鉴于事先阅读THUCTC源码的时候下载了THUCTCNews文书档案集,大致1G多点,已经帮您分好类,放在各样文件夹上面了。为了便利分析,各类环节的中级结果(词频向量,tfidf向量等)也都会存放到本地。为了便于未来标注,各类类的中间结果也是按项目存款和储蓄的。

2. 分类难点

在将文件向量化以往,就能够利用守旧的分类方法了,
例如线性分类法,线性核的svm,rbf核的svm,神经网络分类等办法。笔者在那么些分类器中尝试了前3种,都可以由sklearn库来成功

2.1
从gensim到sklearn的格式转换

八个很窘迫的题材是,gensim中的corpus数据格式,sklearn是无力回天辨认的。即gensim中对向量的象征情势与sklearn须求的不符

在gensim中,向量是稀疏代表的。例如[(0,5),(6,3)]
意思正是说,该向量的第0个成分值为5,第5个元素值为3,其余为0.只是那种代表方法sklearn是力不从心辨认的。sklearn的输入一般是与numpy可能scipy配套的。假如是密集矩阵,就须要输入numpy.array格式的;
借使是稀疏矩阵,则必要输入scipy.sparse.csr_matrix.由于膝下能够转正成前者,而且gensim中向量本人正是稀疏表示,所以那边只讲怎样将gensim中的corpus格式转化成csr_matrix.

scipy的官网去找有关文书档案,能够看到csr_matrix的组织有如下三种艺术。

亚洲必赢官网 1

第3种是由现有的凝聚矩阵来创设稀疏矩阵,第两种不是很精通,第三种创设贰个空矩阵。第伍种和第6种符合我们的渴求。在那之中第两种最为直观,塑造八个数组,分别存款和储蓄每一种成分的行,列和数值即可。

官网给出的言传身教代码如下,还是比较直观的。

row = np.array([0,0,1,2,2,2])col = np.array([0,2,2,0,1,2])data =
np.array([1,2,3,4,5,6])print(csr_matrix((data, (row, col)),
shape=(3,3)).toarray())>>>array([[1, 0, 2],

[0, 0, 3],

[4, 5, 6]])

1

2

3

4

5

6

7

上行下效,gensim转化到csr_matrix的主次能够写成

data= []rows= []cols= []line_count=0forlineinlsi_corpus_total: 
# lsi_corpus_total 是从前由gensim生成的lsi向量    for eleminline:   
    rows.append(line_count)       
cols.append(elem[0])data.append(elem[1])line_count
+=1lsi_sparse_matrix= csr_matrix((data,(rows,cols))) #
稀疏向量lsi_matrix= lsi_sparse_matrix.toarray()  # 密集向量

1

2

3

4

5

6

7

8

9

10

11

12

在将富有数据集都转化成sklearn可用的格式以后,还要将其分成演习集和检验集,比例大致在8:2.上边包车型地铁代码就是有关磨炼集和检验集的更动的

data= []rows= []cols= []line_count=0forlineinlsi_corpus_total: 
  for eleminline:        rows.append(line_count)       
cols.append(elem[0])data.append(elem[1])line_count +=1lsi_matrix=
csr_matrix((data,(rows,cols))).toarray()rarray=np.random.random(size=line_count)train_set=
[]train_tag= []test_set= []test_tag=
[]foriinrange(line_count):ifrarray[i]<0.8:       
train_set.append(lsi_matrix[i,:])       
train_tag.append(tag_list[i])else:       
test_set.append(lsi_matrix[i,:])       
test_tag.append(tag_list[i])

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

2.2 线性判别分析

sklearn中,能够采用sklearn.discriminant_analysis.LinearDiscriminantAnalysis来举行线性分类。

import numpy as npfrom sklearn.discriminant_analysis import
LinearDiscriminantAnalysislda = LinearDiscriminantAnalysis(solver=”svd”,
store_covariance=True)X = np.array([[-1, -1], [-2, -1], [1, 1],
[2, 1]])Y = np.array([1,1,2,2])lda_res = lda.fit(X,
Y)print(lda_res.predict([[-0.8, -1]]))

1

2

3

4

5

6

7

8

在上头的例子中,X代表了演练集。上面的X是1个4*2的矩阵,代表演练集中含有4各个本,各个样本的维度是2维。而Y代表的是练习集中各类本所希望的归类结果。回到文本分类的职分,易知上边代码的X对应于train_set,
而Y对应于train_tag

lda = LinearDiscriminantAnalysis(solver=”svd”,
store_covariance=True)lda_res = lda.fit(train_set,
train_tag)train_pred  = lda_res.predict(train_set)#
陶冶集的展望结果test_pred = lda_res.predict(test_set)#
检验集的预测结果

1

2

3

4

lda_res便是获得的lda模型。 train_pred, test_pred
分别是磨练集和查验集根据取得的lda模型获得的前瞻结果。

尝试批次向量化方法向量长度分类方法陶冶集错误率检验集错误率

1LSI50线性判别16.78%17.18%

2LSI100线性判别14.一成14.四分之一

3LSI200线性判别11.74%11.73%

4LSI400线性判别10.50%10.93%

2.3 SVM分类

由此看来,使用SVM与地点LDA的选取办法相比接近。使用sklearn.svm类能够完毕。可是与lda比较,svm能够承受稀疏矩阵作为输入,那是个好音信。

# clf = svm.SVC()  # 使用RBF核clf = svm.LinearSVC()#
使用线性核clf_res = clf.fit(train_set,train_tag)train_pred  =
clf_res.predict(train_set)test_pred  = clf_res.predict(test_set)

1

2

3

4

5

能够运用RBF核,也足以运用线性核。可是要小心,RBF核在数据集不太足够的情况下有很好的结果,不过当数据量极大是就不太明了,而且运转速度越发十分之一点也非常快!
所以我推荐应用线性核,运算速度快,而且效果比线性判别稍好有的

尝试批次向量化方法向量长度分类方法磨练集错误率检验集错误率

5LSI50svm_linear12.31%12.52%

6LSI100svm_linear10.13%10.20%

7LSI200svm_linear8.75%8.98%

8LSI400svm_linear7.70%7.89%

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图