IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 天池-新闻文本分类-task1机器学习算法(未完待续) -> 正文阅读

[人工智能]天池-新闻文本分类-task1机器学习算法(未完待续)

一、文本挖掘原理

1 分词的基本原理

??现代分词都是基于统计的分词,而统计的样本内容来自于一些标准的语料库。假如有一个句子:“小明来到荔湾区”,我们期望语料库统计后分词的结果是:“小明/来到/荔湾/区”,而不是“小明/来到/荔/湾区”。那么如何做到这一点呢?
??从统计的角度,我们期望"小明/来到/荔湾/区"这个分词后句子出现的概率要比“小明/来到/荔/湾区”大。如果用数学的语言来说说,如果有一个句子 S S S,它有m种分词选项如下: A 11 A 12 . . . A 1 n 1 A_{11}A_{12}...A_{1n_1} A11?A12?...A1n1?? A 21 A 22 . . . A 2 n 2 A_{21}A_{22}...A_{2n_2} A21?A22?...A2n2?? . . . . . . . . . . . . ...... ...... ............ A m 1 A m 2 . . . A m n m A_{m1}A_{m2}...A_{mn_m} Am1?Am2?...Amnm??

??其中下标 n i n_i ni?代表第 i i i种分词的词个数。如果我们从中选择了最优的第 r r r种分词方法,那么这种分词方法对应的统计分布概率应该最大,即: r = a r g ?? m a x ? i P ( A i 1 , A i 2 , . . . , A i n i ) r = \underbrace{arg\;max}_iP(A_{i1},A_{i2},...,A_{in_i}) r=i argmax??P(Ai1?,Ai2?,...,Aini??)

??但是我们的概率分布 P ( A i 1 , A i 2 , . . . , A i n i ) P(A_{i1},A_{i2},...,A_{in_i}) P(Ai1?,Ai2?,...,Aini??)并不好求出来,因为它涉及到 n i n_i ni?个分词的联合分布。在NLP中,为了简化计算,我们通常使用马尔科夫假设,即每一个分词出现的概率仅仅和前一个分词有关,即: P ( A i j ∣ A i 1 , A i 2 , . . . , A i ( j ? 1 ) ) = P ( A i j ∣ A i ( j ? 1 ) ) P(A_{ij}|A_{i1},A_{i2},...,A_{i(j-1)}) = P(A_{ij}|A_{i(j-1)}) P(Aij?Ai1?,Ai2?,...,Ai(j?1)?)=P(Aij?Ai(j?1)?)
??则我们的联合分布就好求了,即: P ( A i 1 , A i 2 , . . . , A i n i ) = P ( A i 1 ) P ( A i 2 ∣ A i 1 ) P ( A i 3 ∣ A i 2 ) . . . P ( A i n i ∣ A i ( n i ? 1 ) ) P(A_{i1},A_{i2},...,A_{in_i}) = P(A_{i1})P(A_{i2}|A_{i1})P(A_{i3}|A_{i2})...P(A_{in_i}|A_{i(n_i-1)}) P(Ai1?,Ai2?,...,Aini??)=P(Ai1?)P(Ai2?Ai1?)P(Ai3?Ai2?)...P(Aini??Ai(ni??1)?)

??而通过我们的标准语料库,我们可以近似的计算出所有的分词之间的二元条件概率,比如任意两个词 w 1 , w 2 w_1,w_2 w1?,w2?,它们的条件概率分布可以近似的表示为: P ( w 2 ∣ w 1 ) = P ( w 1 , w 2 ) P ( w 1 ) ≈ f r e q ( w 1 , w 2 ) f r e q ( w 1 ) P(w_2|w_1) = \frac{P(w_1,w_2)}{P(w_1)} \approx \frac{freq(w_1,w_2)}{freq(w_1)} P(w2?w1?)=P(w1?)P(w1?,w2?)?freq(w1?)freq(w1?,w2?)? P ( w 1 ∣ w 2 ) = P ( w 2 , w 1 ) P ( w 2 ) ≈ f r e q ( w 1 , w 2 ) f r e q ( w 2 ) P(w_1|w_2) = \frac{P(w_2,w_1)}{P(w_2)} \approx \frac{freq(w_1,w_2)}{freq(w_2)} P(w1?w2?)=P(w2?)P(w2?,w1?)?freq(w2?)freq(w1?,w2?)?

??其中 f r e q ( w 1 , w 2 ) freq(w_1,w_2) freq(w1?,w2?)表示 w 1 , w 2 w_1,w_2 w1?,w2?在语料库中相邻一起出现的次数,而其中 f r e q ( w 1 ) , f r e q ( w 2 ) freq(w_1),freq(w_2) freq(w1?),freq(w2?)分别表示 w 1 , w 2 w_1,w_2 w1?,w2?在语料库中出现的统计次数。

??利用语料库建立的统计概率,对于一个新的句子,我们就可以通过计算各种分词方法对应的联合分布概率,找到最大概率对应的分词方法,即为最优分词。

1.2 N元模型

??当然,你会说,只依赖于前一个词太武断了,我们能不能依赖于前两个词呢?即: P ( A i 1 , A i 2 , . . . , A i n i ) = P ( A i 1 ) P ( A i 2 ∣ A i 1 ) P ( A i 3 ∣ A i 1 , A i 2 ) . . . P ( A i n i ∣ A i ( n i ? 2 ) , A i ( n i ? 1 ) ) P(A_{i1},A_{i2},...,A_{in_i}) = P(A_{i1})P(A_{i2}|A_{i1})P(A_{i3}|A_{i1},A_{i2})...P(A_{in_i}|A_{i(n_i-2)},A_{i(n_i-1)}) P(Ai1?,Ai2?,...,Aini??)=P(Ai1?)P(Ai2?Ai1?)P(Ai3?Ai1?Ai2?)...P(Aini??Ai(ni??2)?Ai(ni??1)?)

??这样也是可以的,我们一般称只依赖于前一个词的模型为二元模型(Bi-Gram model),而依赖于前两个词的模型为三元模型。以此类推,一直到通用的 N N N元模型。

??在实际应用中, N N N一般都较小,一般都小于4,主要原因是N元模型概率分布的空间复杂度为 O ( ∣ V ∣ N ) O(|V|^N) O(VN),其中 ∣ V ∣ |V| V为语料库大小,而 N N N为模型的元数,当 N N N增大时,复杂度呈指数级的增长。(二元模型前后两个词都有V种选择)常用汉字三四千,但是常用词是20w,二元模型就是400亿可能。

?? N N N元模型的分词方法虽然很好,但是要在实际中应用也有很多问题:

  • 某些生僻词,或者相邻分词联合分布在语料库中没有,概率为0。这种情况我们一般会使用 拉普拉斯平滑,即给它一个较小的概率值。
  • 第二个问题是如果句子长,分词有很多情况,计算量也非常大,这时我们可以用下一节维特比算法来优化算法时间复杂度。

1.3 维特比算法与分词

??为了简化原理描述,我们本节的讨论都是以二元模型为基础。

??对于一个有很多分词可能的长句子,我们当然可以用暴力方法去计算出所有的分词可能的概率,再找出最优分词方法。但是用维特比算法可以大大简化求出最优分词的时间。具体介绍参考《文本挖掘》

1. 4常用分词工具

??简单的英文分词不需要任何工具,通过空格和标点符号就可以分词了,而进一步的英文分词推荐使用nltk。对于中文分词,则推荐用结巴分词(jieba)。

??分词是文本挖掘的预处理的重要的一步,分词完成后,我们可以继续做一些其他的特征工程,比如向量化(vectorize),TF-IDF以及Hash trick。

2.文本挖掘预处理之向量化与Hash Trick

??分词后,如果我们是做文本分类聚类,则后面关键的特征预处理步骤有向量化或向量化的特例Hash Trick。

2.1 词袋模型

??词袋模型(Bag of Words,简称BoW)。词袋模型假设我们不考虑文本中词与词之间的上下文关系,仅仅只考虑所有词的权重。而权重与词在文本中出现的频率有关。

??词袋模型首先会进行分词,在分词之后,通过统计每个词在文本中出现的次数,我们就可以得到该文本基于词的特征,如果将各个文本样本的这些词与对应的词频放在一起,就是我们常说的向量化。向量化完毕后一般也会使用TF-IDF进行特征的权重修正,再将特征进行标准化。 再进行一些其他的特征工程后,就可以将数据带入机器学习算法进行分类聚类了。

??总结下词袋模型的三部曲:分词(tokenizing),TF-IDF修订词特征值(counting)与标准化(normalizing)。
    
??当然,词袋模型有很大的局限性,因为它仅仅考虑了词频,没有考虑上下文的关系,因此会丢失一部分文本的语义。但是大多数时候,如果我们的目的是分类聚类,则词袋模型表现的很好。
2. 词向量化

2.2 词袋模型之向量化

??在词袋模型的统计词频这一步,我们会得到该文本中所有词的词频,有了词频,我们就可以用词向量表示这个文本。例如直接用scikit-learn的CountVectorizer类来完成文本的词频统计与向量化,代码如下:

??完整代码参见我的github:https://github.com/ljpzzz/machinelearning/blob/master/natural-language-processing/hash_trick.ipynb

from sklearn.feature_extraction.text import CountVectorizer  
vectorizer=CountVectorizer()
corpus=["I come to China to travel", 
    "This is a car polupar in China",          
    "I love tea and Apple ",   
    "The work is to write some papers in science"] 
print vectorizer.fit_transform(corpus)

我们看看对于上面4个文本的处理输出如下:

(0, 16)	1
(0, 3)	1
(0, 15)	2
(0, 4)	1
(1, 5)	1
(1, 9)	1
(1, 2)	1
(1, 6)	1
(1, 14)	1
(1, 3)	1
(2, 1)	1
(2, 0)	1
(2, 12)	1
(2, 7)	1
(3, 10)	1
(3, 8)	1
(3, 11)	1
(3, 18)	1
(3, 17)	1
(3, 13)	1
(3, 5)	1
(3, 6)	1
(3, 15)	1

??可以看出4个文本的词频已经统计出,在输出中,左边的括号中的第一个数字是文本的序号,第2个数字是词的序号,注意词的序号是基于所有的文档的。第三个数字就是我们的词频。

??我们可以进一步看看每个文本的词向量特征和各个特征代表的词,代码如下:

print vectorizer.fit_transform(corpus).toarray()
print vectorizer.get_feature_names()

输出如下:

[[0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 2 1 0 0]
	 [0 0 1 1 0 1 1 0 0 1 0 0 0 0 1 0 0 0 0]
	 [1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0]
	 [0 0 0 0 0 1 1 0 1 0 1 1 0 1 0 1 0 1 1]]
	[u'and', u'apple', u'car', u'china', u'come', u'in', u'is', u'love', u'papers', u'polupar', u'science', u'some', u'tea', u'the', u'this', u'to', u'travel', u'work', u'write']

??可以看到我们一共有19个词,所以4个文本都是19维的特征向量。而每一维的向量依次对应了下面的19个词。另外由于词"I"在英文中是停用词,不参加词频的统计。

??由于大部分的文本都只会使用词汇表中的很少一部分的词,因此我们的词向量中会有大量的0。也就是说词向量是稀疏的。在实际应用中一般使用稀疏矩阵来存储。

??将文本做了词频统计后,我们一般会通过TF-IDF进行词特征值修订,这部分我们后面再讲。

??向量化的方法很好用,也很直接,但是在有些场景下很难使用,比如分词后的词汇表非常大,达到100万+,此时如果我们直接使用向量化的方法,将对应的样本对应特征矩阵载入内存,有可能将内存撑爆,在这种情况下我们怎么办呢?第一反应是我们要进行特征的降维,说的没错!而Hash Trick就是非常常用的文本特征降维方法。

2.3 Hash Trick

??在大规模的文本处理中,由于特征的维度对应分词词汇表的大小,所以维度可能非常恐怖,此时需要进行降维,不能直接用我们上一节的向量化方法。而最常用的文本降维方法是Hash Trick。
??在Hash Trick里,我们会定义一个特征Hash后对应的哈希表的大小,这个哈希表的维度会远远小于我们的词汇表的特征维度,因此可以看成是降维。具体的方法是,对应任意一个特征名,我们会用Hash函数找到对应哈希表的位置,然后将该特征名对应的词频统计值累加到该哈希表位置。如果用数学语言表示,假如哈希函数 h h h使第 i i i个特征哈希到位置 j j j,即 h ( i ) = j h(i)=j h(i)=j,则第 i i i个原始特征的词频数值 ? ( i ) \phi(i) ?(i)将累加到哈希后的第 j j j个特征的词频数值 ? ˉ \bar{\phi} ?ˉ?上,即: ? ˉ ( j ) = ∑ i ∈ J ; h ( i ) = j ? ( i ) \bar{\phi}(j) = \sum_{i\in \mathcal{J}; h(i) = j}\phi(i) ?ˉ?(j)=iJ;h(i)=j??(i)

??其中 J \mathcal{J} J是原始特征的维度。
??但是上面的方法有一个问题,有可能两个原始特征的哈希后位置在一起导致词频累加特征值突然变大,为了解决这个问题,出现了hash Trick的变种signed hash trick,此时除了哈希函数 h h h,我们多了一个一个哈希函数: ξ : N → ± 1 \xi : \mathbb{N} \to {\pm 1} ξ:N±1

??此时我们有 ? ˉ ( j ) = ∑ i ∈ J ; h ( i ) = j ξ ( i ) ? ( i ) \bar{\phi}(j) = \sum_{i\in \mathcal{J}; h(i) = j}\xi(i)\phi(i) ?ˉ?(j)=iJ;h(i)=j?ξ(i)?(i)

??这样做的好处是,哈希后的特征仍然是一个无偏的估计,不会导致某些哈希位置的值过大。
??在scikit-learn的HashingVectorizer类中,实现了基于signed hash trick的算法,这里我们就用HashingVectorizer来实践一下Hash Trick,为了简单,我们使用上面的19维词汇表,并哈希降维到6维。当然在实际应用中,19维的数据根本不需要Hash Trick,这里只做一个演示,代码如下:

from sklearn.feature_extraction.text import HashingVectorizer 
vectorizer2=HashingVectorizer(n_features = 6,norm = None)
print vectorizer2.fit_transform(corpus)
    #输出如下:

 (0, 1)	2.0
 (0, 2)	-1.0
 (0, 4)	1.0
 (0, 5)	-1.0
 (1, 0)	1.0
 (1, 1)	1.0
 (1, 2)	-1.0
 (1, 5)	-1.0
 (2, 0)	2.0
 (2, 5)	-2.0
 (3, 0)	0.0
 (3, 1)	4.0
 (3, 2)	-1.0
 (3, 3)	1.0
 (3, 5)	-1.0

??大家可以看到结果里面有负数,这是因为我们的哈希函数 ξ \xi ξ可以哈希到1或者-1导致的。

??和PCA类似,Hash Trick降维后的特征我们已经不知道它代表的特征名字和意义。此时我们不能像上一节向量化时候可以知道每一列的意义,所以Hash Trick的解释性不强。

2.4 向量化与Hash Trick小结

??一般来说,只要词汇表的特征不至于太大,大到内存不够用,肯定是使用一般意义的向量化比较好。因为向量化的方法解释性很强,我们知道每一维特征对应哪一个词,进而我们还可以使用TF-IDF对各个词特征的权重修改,进一步完善特征的表示。

??而Hash Trick用大规模机器学习上,此时我们的词汇量极大,使用向量化方法内存不够用,而使用Hash Trick降维速度很快,降维后的特征仍然可以帮我们完成后续的分类和聚类工作。当然由于分布式计算框架的存在,其实一般我们不会出现内存不够的情况。因此,实际工作中我使用的都是特征向量化。

3. 文本挖掘预处理之TF-IDF

3.1 TF-IDF概述

??TF-IDF是Term Frequency - Inverse Document Frequency的缩写,即“词频-逆文本频率”。它由两部分组成,TF和IDF。

??IDF反应了一个词在所有文本中出现的频率(也可以理解为词的信息量),如果一个词在很多的文本中出现,那么它的IDF值应该低,比如上文中的“to”。而反过来如果一个词在比较少的文本中出现,那么它的IDF值应该高。比如一些专业的名词如“Machine Learning”。这样的词IDF值应该高。一个极端的情况,如果一个词在所有的文本中都出现,那么它的IDF值应该为0。

??一个词 x x x的IDF的基本公式如下: I D F ( x ) = l o g N N ( x ) IDF(x) = log\frac{N}{N(x)} IDF(x)=logN(x)N?

??其中, N N N代表语料库中文本的总数,而 N ( x ) N(x) N(x)代表语料库中包含词 x x x的文本总数。为什么IDF的基本公式应该是是上面这样的而不是像 N / N ( x ) N/N(x) N/N(x)这样的形式呢?这就涉及到信息论相关的一些知识了。感兴趣的朋友建议阅读吴军博士的《数学之美》第11章。

??某一个生僻词在语料库中没有,这样我们的分母为0, IDF没有意义了。所以常用的IDF我们需要做一些平滑,使语料库中没有出现的词也可以得到一个合适的IDF值。平滑的方法有很多种,最常见的IDF平滑后的公式之一为: I D F ( x ) = l o g N + 1 N ( x ) + 1 + 1 IDF(x) = log\frac{N+1}{N(x)+1} + 1 IDF(x)=logN(x)+1N+1?+1

??有了IDF的定义,我们就可以计算某一个词的TF-IDF值了: T F ? I D F ( x ) = T F ( x ) ? I D F ( x ) TF-IDF(x) = TF(x) * IDF(x) TF?IDF(x)=TF(x)?IDF(x)

??这个值可以表示一个词在文档中的权重。其中 T F ( x ) TF(x) TF(x)指词 x x x在 当前文本中的词频。IDF是一个全量信息,综合全局文档得出每个词的IDF值。
??TF-IDF的缺点是没有考虑词的组合搭配,优点是运算量小,符合直觉,解释性强。在Solr elastic-Search 和luence这些搜索引擎中广泛使用。

3.2 用scikit-learn进行TF-IDF预处理

在scikit-learn中,有两种方法进行TF-IDF的预处理,完整代码参见github

  1. 用CountVectorizer类向量化之后再调用TfidfTransformer类进行预处理。
  2. 直接用TfidfVectorizer完成向量化与TF-IDF预处理。

首先我们来看第一种方法,CountVectorizer+TfidfTransformer的组合,代码如下:

from sklearn.feature_extraction.text import TfidfTransformer  
from sklearn.feature_extraction.text import CountVectorizer  

corpus=["I come to China to travel", 
    "This is a car polupar in China",          
    "I love tea and Apple ",   
    "The work is to write some papers in science"] 

vectorizer=CountVectorizer()

transformer = TfidfTransformer()
tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))  
print tfidf

(0, 4)	0.442462137895
(0, 15)	0.697684463384
(0, 3)	0.348842231692
(0, 16)	0.442462137895
(1, 3)	0.357455043342
(1, 14)	0.453386397373
(1, 6)	0.357455043342
(1, 2)	0.453386397373
(1, 9)	0.453386397373
(1, 5)	0.357455043342
(2, 7)	0.5
(2, 12)	0.5
(2, 0)	0.5
(2, 1)	0.5
(3, 15)	0.281131628441
(3, 6)	0.281131628441
(3, 5)	0.281131628441
(3, 13)	0.356579823338
(3, 17)	0.356579823338
(3, 18)	0.356579823338
(3, 11)	0.356579823338
(3, 8)	0.356579823338
(3, 10)	0.356579823338

在输出中,左边的括号中的第一个数字是文本的序号,第2个数字是词的序号,注意词的序号是基于所有的文档的。第三个数字就是TF-IDF值。
现在我们用TfidfVectorizer一步到位,代码如下:

from sklearn.feature_extraction.text import TfidfVectorizer
tfidf2 = TfidfVectorizer()
re = tfidf2.fit_transform(corpus)
print re

3.4 TF-IDF小结

??TF-IDF是非常常用的文本挖掘预处理基本步骤,但是如果预处理中使用了Hash Trick,则一般就无法使用TF-IDF了,因为Hash Trick后我们已经无法得到哈希后的各特征的IDF的值。使用了IF-IDF并标准化以后,我们就可以使用各个文本的词特征向量作为文本的特征,进行分类或者聚类分析。

??当然TF-IDF不光可以用于文本挖掘,在信息检索等很多领域都有使用。因此值得好好的理解这个方法的思想。

三、代码解析

下面分类代码的本质,都是讲文本text经过TF/TF-IDF处理之后,转换成为文章向量(文章向量维度表示词向量的长度),之后将文章向量经过各种分类器,进行分类。本质上和fasttext、textcnn没有区别。(向量和label进行训练拟合,进行分类)

max_features表示每篇文章的词向量维度,即一篇文章设置为多少维向量来表示
ngram_range=(1,3)表示采样多元语言模型,从1元到3元。即包括单个词、双词到三个词。
其它参数参考:《sklearn: TfidfVectorizer 中文处理及一些使用参数》《Python中的TfidfVectorizer参数解析》

3.1 TF + RidgeClassifier

max_features可以设置每篇文章的词向量维度,todense方法可以将稀疏矩阵转换为密集矩阵。

#从google云盘上加载数据
from google.colab import drive
drive.mount('/content/drive')
import os
os.chdir('/content/drive/MyDrive/transformers/天池-入门NLP - 新闻文本分类')
# Count Vectors词频
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
#读取训练集前15000行数据测试
train_df = pd.read_csv('./train_set.csv', sep='\t', nrows=15000)
# 将一篇文章映射为3000维度的向量
vectorizer = CountVectorizer(max_features=3000)
train_test = vectorizer.fit_transform(train_df['text'])
print(train_test[:1000])

3.1.2 max_features举例

在大规模语料上训练TFIDF会得到非常多的词语,如果再使用了ngram_range,那么我们词表的大小就会爆炸。出于时间和空间效率的考虑,可以限制最多使用多少个词语,模型会优先选取词频高的词语留下。

(0, 852)	6
(0, 2540)	4
(0, 1061)	1
(0, 446)	2
:	:
(999, 1387)	2
(999, 255)	1
(999, 2096)	2
(999, 759)	2

如果设置vectorizer = CountVectorizer(max_features=1000),则结果如下:

(0, 278)	6
(0, 143)	2
(0, 116)	1
:	:
(999, 835)	2
(999, 416)	2
(999, 103)	1
(999, 620)	1

3.1.3 todense方法

用todense方法可以将稀疏矩阵转换为密集矩阵:

print(train_test)
[[0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]
 [0 0 0 ... 0 0 0]
 ...
 [0 0 0 ... 0 0 0]
 [0 0 0 ... 0 1 0]
 [0 0 0 ... 0 0 0]]

其实就是1-1000篇文章的列向量(二维列表,第一个维度是文章,第二个维度是文章的词)转换1000*3000的矩阵。

或者看这个例子:

from sklearn.feature_extraction.text import CountVectorizer  
vectorizer=CountVectorizer()
corpus=["I come to China to travel", 
    "This is a car polupar in China",          
    "I love tea and Apple ",   
    "The work is to write some papers in science"] 
print(vectorizer.fit_transform(corpus).todense())

[[0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 2 1 0 0]
 [0 0 1 1 0 1 1 0 0 1 0 0 0 0 1 0 0 0 0]
 [1 1 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0]
 [0 0 0 0 0 1 1 0 1 0 1 1 0 1 0 1 0 1 1]]
print(vectorizer.fit_transform(corpus))

(0, 4)	1
(0, 15)	2
(0, 3)	1
(0, 16)	1
(1, 3)	1
(1, 14)	1
(1, 6)	1
(1, 2)	1
(1, 9)	1
(1, 5)	1
(2, 7)	1
(2, 12)	1
(2, 0)	1
(2, 1)	1
(3, 15)	1
(3, 6)	1
(3, 5)	1
(3, 13)	1
(3, 17)	1
(3, 18)	1
(3, 11)	1
(3, 8)	1
(3, 10)	1

使用岭回归RidgeClassifier分类器训练模型

from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score
clf = RidgeClassifier()
clf.fit(train_test[:10000], train_df['label'].values[:10000])

val_pred = clf.predict(train_test[10000:])
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
# 0.7423139613717681

没有使用todense方法,整个训练时间是1分钟,准确率0.742。

clf = RidgeClassifier()
clf.fit(train_test[:10000].todense(), train_df['label'].values[:10000])

val_pred = clf.predict(train_test[10000:].todense())
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
#0.7411137174103894

使用todense方法训练时间12秒,大大缩短,但是准确率0.741,稍有下降。

3.1.4 F1_score(sklearn)

f1_score(y_true, y_pred, labels=None, pos_label=1, average='binary', sample_weight=None, zero_division='warn')

#参数含义
average : string, [None, 'binary' (default), 'micro', 'macro', 'samples', 'weighted']

'binary':默认值,表示二分类。
'micro' :通过先计算总体的TP,FN和FP的数量,再计算F1
'macro' :分别计算每个类别的F1,然后做平均(各类别F1的权重相同)当小类很重要时会出问题,因为该macro-averging方法是对性能的平均。另一方面,该方法假设所有分类都是一样重要的,因此macro-averaging方法会对小类的性能影响很大。
samples:应用在 multilabel问题上。它不会计算每个类,相反,它会在评估数据中,通过计算真实类和预测类的差异的metrics,来求平均(sample_weight-weighted)
average:average=None将返回一个数组,它包含了每个类的得分.
weighted: 对于不均衡数量的类来说,计算二分类metrics的平均,通过在每个类的score上进行加权实现。

参考:sklearn中 F1-micro 与 F1-macro区别和计算原理F1_score(sklearn)

3.2 TF-IDF + RidgeClassifier

import pandas as pd

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score

train_df = pd.read_csv('../data/train_set.csv', sep='\t', nrows=15000)

tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])
print(train_test[:1000])

可以看到跟3.1TF相比,词频转换成了TF-IDF值

(0, 2865)	0.021535770236833403
(0, 2806)	0.02001603028943581
:	:
(999, 1722)	0.044467254252004755
(999, 600)	0.0856488025571623
print(train_test[:1000].todense())

[[0.         0.         0.         ... 0.         0.         0.        ]
 [0.         0.         0.         ... 0.         0.         0.        ]
 ...
 [0.         0.         0.         ... 0.         0.         0.00481137]
 [0.         0.         0.         ... 0.         0.         0.        ]]

TfidfVectorizer参数:
ngram_range: tuple(min_n, max_n)
要提取的n-gram的n-values的下限和上限范围,在min_n <= n <= max_n区间的n的全部值

clf = RidgeClassifier()
clf.fit(train_test[:10000], train_df['label'].values[:10000])

val_pred = clf.predict(train_test[10000:])
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
#0.8721598830546126
  • 正常用时71秒,f1=0.87216。
  • 使用todense方法训练时间70秒,f1=0.87194。

TF-IDF的计算时间比TF长很多。
关于RidgeClassifier岭回归分类器,参考《Skleran-线性模型-Ridge/岭回归》

3.3 TF-IDF+朴素贝叶斯

# TF-IDF +  高斯朴素贝叶斯
import pandas as pd

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import f1_score

train_df = pd.read_csv('./data/train_set.csv', sep='\t', nrows=30000)
# 将一篇文章映射为3000维度的向量
tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])
clf = GaussianNB()
clf.fit(train_test[:20000].toarray(), train_df['label'].values[:20000])

val_pred = clf.predict(train_test[20000:].toarray())
print(f1_score(train_df['label'].values[20000:], val_pred, average='macro'))
# 0.7286027535218247,用时126秒

3.4 TF-IDF+决策树

# TF-IDF +  决策树
import pandas as pd

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import f1_score

train_df = pd.read_csv('./data/train_set.csv', sep='\t', nrows=30000)
# 将一篇文章映射为3000维度的向量
tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])
clf = DecisionTreeClassifier(criterion="entropy")
clf.fit(train_test[:20000].todense(), train_df['label'].values[:20000])

val_pred = clf.predict(train_test[20000:].todense())
print(f1_score(train_df['label'].values[20000:], val_pred, average='macro'))

# 0.7019031297922049,用时193秒

3.5 TF-IDF+随机森林

# TF-IDF +  随机森林

import pandas as pd

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import f1_score

train_df = pd.read_csv('./data/train_set.csv', sep='\t', nrows=30000)
# 将一篇文章映射为3000维度的向量
tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])
clf = RandomForestClassifier(
        n_estimators=10, criterion='gini',
        max_depth=None,min_samples_split=2, 
        min_samples_leaf=1, min_weight_fraction_leaf=0.0,
        max_features='auto', max_leaf_nodes=None,
        min_impurity_split=1e-07,bootstrap=True,
        oob_score=False, n_jobs=1, 
        random_state=None, verbose=0,
        warm_start=False, class_weight=None)
clf.fit(train_test[:20000].todense(), train_df['label'].values[:20000])

val_pred = clf.predict(train_test[20000:].todense())
print(f1_score(train_df['label'].values[20000:], val_pred, average='macro'))
#0.7456517053768087,用时127秒

3.6 TF-IDF+XGBoost
GBDT也叫梯度提升决策树。学习资料:XGBoost入门系列第一讲

import pandas as pd

from sklearn.feature_extraction.text import TfidfVectorizer

from xgboost.sklearn import XGBClassifier
from sklearn.metrics import f1_score
train_df = pd.read_csv('./data/train_set.csv', sep='\t', nrows=30000)
# 将一篇文章映射为3000维度的向量
tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])
clf = XGBClassifier(min_child_weight=6,max_depth=15,
                            objective='multi:softmax',num_class=5)
clf.fit(train_test[:20000].todense(), train_df['label'].values[:20000])

val_pred = clf.predict(train_test[20000:].todense())
print(f1_score(train_df['label'].values[20000:], val_pred, average='macro'))
#0.9024422794080935,111分钟

3.7 TF-IDF+LightGBM

import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
import lightgbm as lgb
from sklearn.metrics import f1_score
train_df = pd.read_csv('./data/train_set.csv', sep='\t', nrows=30000)
# 将一篇文章映射为3000维度的向量
tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])
params_sklearn = {
    'learning_rate':0.1,
    'max_bin':150,
    'num_leaves':32,    
    'max_depth':11,
    'reg_alpha':0.1,
    'reg_lambda':0.2,   
    'objective':'multiclass',
    'n_estimators':300,
    #'class_weight':weight
}

clf = lgb.LGBMClassifier(**params_sklearn)
clf.fit(train_test[:20000].todense(), train_df['label'].values[:20000])

val_pred = clf.predict(train_test[20000:].todense())
print(f1_score(train_df['label'].values[20000:], val_pred, average='macro'))
#0.9027526863541893,用时26分12秒
序号算法f1-score时间
1RidgeClassifier(max_features=3000,下同)0.8895146秒
2高斯朴素贝叶斯0.7286126秒
3决策树0.7019193秒
4随机森林0.7456127秒
5GBDT0.9024111分钟
6lgb0.902726分钟
7RidgeClassifier(max_features=4000,stop_words=[‘3750’,‘648’,‘900’])0.8994156秒
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-10-24 14:56:26  更:2021-10-24 14:58:45 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 8:22:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码