文本分类方法总结

背景

此文是对NLP文本分类文章的个人知识盲点补充。此文总结类,传统文本分类方法,深度学习文本分类,词向量三种方式的常用文本分类方法,并配上足够的代码,是不可夺得的好文。

Multi class log loss

对数损失函数主要用于对分类器的准确度进行量化。分类器需要提供对输入的所属的每个类别的概率值。
L ( Y , P ( Y ∣ X ) ) = − log ⁡ P ( Y ∣ X ) = − 1 N ∑ i = 1 N ∑ j = 1 M y i j log ⁡ ( p i j ) L(Y, P(Y | X))=-\log P(Y | X)=-\frac{1}{N} \sum_{i=1}^{N} \sum_{j=1}^{M} y_{i j} \log \left(p_{i j}\right) L(Y,P(YX))=logP(YX)=N1i=1Nj=1Myijlog(pij)

文本预处理

由于语料库准备成本较高,通常用第三方预训练好模型处理,下载一般要下载语料库,安装比较繁琐。自然语言处理综合一文已经详细的总结了NLP领域的python工具包,这里主要对我的知识盲点进行记录。

NLP中对文本的预处理常用步骤有:

  • Normalization:去除大小写和标点符号
  • Tokenization:把一个string根据单词间空格打断成一个个单词放入list中。
  • Stop Word Removal:移除token中的停止词,英语如:the, you, it等词语。
  • Stemming and Lemmatization:把单词变成主要词根形式,减少复数、动名词变化等形式;把单词的过去式现在时等多种形态变成原始形态,减少同一个单词的差异性。

gensim是词嵌入训练的库

# 自行训练词向量
from gensim.models import Word2Vec
sentences = [["cat", "say", "meow"], ["dog", "say", "woof"]]
model = Word2Vec(min_count=1)
model.build_vocab(sentences)    #搭建语料库
model.train(sentences, total_examples=model.corpus_count, epochs=model.epochs)  #训练
model.wv['cat']    #查看词向量
model.wv.index2word #查看词语
model.wv.vectors #查看词向量
model.save('/word2vec')    #保存模型
model.vocabulary.load('/word2vec')    #读取模型

TF-IDF

又称Term Frequency - Inverse Document Frequency,是一种统计方法,用以评估一字词对于一个语料库重的一份文件的重要程度。某字词的重要程度是根据某字词出现次数的多少来决定。网上已经有许多优秀的博客讲诉原理,在此只强调IDF中语料库的文档总数概念,可类比为图书馆里所有的书,包含词条w的文档数:图书馆中有“中国”这个词的书。

# 两种方法得到Tfidf词向量
corpus=["dog cat fish","dog cat cat","fish bird", 'bird']

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

vectorizer=CountVectorizer()
v1 = vectorizer.fit_transform(corpus) 
print(v1) # (0, 3) 1 第0个列表元素,**词典中索引为3的元素**, 词频
# vectorizer.vocabulary_ 获取词典
# vectorizer.get_feature_names() 获取词袋模型中的所有词语
transformer = TfidfTransformer() 
tfidf = transformer.fit_transform(v1)  

# 2
from sklearn.feature_extraction.text import TfidfVectorizer
# token_pattern=r"(?u)\b\w\w+\b"  \b:表示字母数字与非字母数字的边界,     非字母数字与字母数字的边界。

tfidf2 = TfidfVectorizer()
tfidf = tfidf2.fit_transform(corpus)

# 用TruncatedSVD做文本主题分析,类似词向量
from sklearn.decomposition import TruncatedSVD  

lsa = TruncatedSVD(n_components=3)               
X2 = lsa.fit_transform(tfidf) # 返回N*M矩阵。N是文档数,M是components数

Python super()函数

super()是用于调用父类的一个方法,这里用一个例子直接说明。可以用于稍微修改TfidfVectorizer类

class FooParent(object):
    def __init__(self):
        self.parent = 'I\'m the parent.'
        print ('Parent')
    def bar(self,message):
        print ("%s from Parent" % message)
 
class FooChild(FooParent):
    def __init__(self):
        # super(FooChild,self) 首先找到 FooChild 的父类(就是类 FooParent),然后把类 FooChild 的对象转换为类 FooParent 的对象
        super(FooChild,self).__init__()    
        print ('Child')      
    def bar(self,message):
        super(FooChild, self).bar(message)
        print ('Child bar fuction')
        print (self.parent)
 
if __name__ == '__main__':
    fooChild = FooChild()
    fooChild.bar('HelloWorld')
    Parent
# Child
# HelloWorld from Parent
# Child bar fuction
# I'm the parent.

Sentence2Vector

文中提了一种从word2vec做Sentence2Vector的做法,将一句话每个词的word2vec计算出后相加后做归一化。根据其它博客可知,一般操作是会加上每个词语的权重。算法分成两步

  • 输入是每个词的词向量,句子词语集合,超参数,每个词语的频率。对句子中的每个词语求权重后相加求平均,得到一句话的向量。
  • 使用PCA/SVD对向量值进行修改。
    • 去除句子中的公共部分。方法是通过PCA求出主成分后用句子向量减去。
pca = PCA(n_components=embedding_size)
pca.fit(np.array(sentence_set))
u = pca.components_[0] 

文本分类方法总结_第1张图片

from gensim.test.utils import common_texts
from gensim.models import Word2Vec

model = Word2Vec(common_texts, size=100, window=5, min_count=1, workers=4)

def sen2vec(s):
    M = []
    for w in s:
        M.append(model[w])
    M = np.array(M)
    v = M.sum(axis=0)
    return v / (np.sqrt(v**2).sum())

x = [sen2vec(s) for s in common_texts]

Keras tokenizer

文中还用到了keras tokenizer,笔者对其进行了简单的总结

import keras.preprocessing.text as T
from keras.preprocessing.text import Tokenizer
 
text1='some thing to eat'
text2='some thing to drink'
texts=[text1,text2]
 
print T.text_to_word_sequence(text1)  #以空格区分,中文也不例外 ['some', 'thing', 'to', 'eat']
print T.one_hot(text1,10)  #[7, 9, 3, 4] -- (10表示数字化向量为10以内的数字)
print T.one_hot(text2,10)  #[7, 9, 3, 1]
 
tokenizer = Tokenizer(num_words=None) #num_words:None或整数,处理的最大单词数量。少于此数的单词丢掉
tokenizer.fit_on_texts(texts)
print( tokenizer.word_counts) #[('some', 2), ('thing', 2), ('to', 2), ('eat', 1), ('drink', 1)]
print( tokenizer.word_index) #{'some': 1, 'thing': 2,'to': 3 ','eat': 4, drink': 5}
print( tokenizer.word_docs) #{'some': 2, 'thing': 2, 'to': 2, 'drink': 1,  'eat': 1}
print( tokenizer.index_docs) #{1: 2, 2: 2, 3: 2, 4: 1, 5: 1}
 
# num_words=多少会影响下面的结果,行数=num_words
print( tokenizer.texts_to_sequences(texts)) #得到词索引[[1, 2, 3, 4], [1, 2, 3, 5]]
print( tokenizer.texts_to_matrix(texts))  # 矩阵化=one_hot
[[ 0.,  1.,  1.,  1.,  1.,  0.,  0.,  0.,  0.,  0.],
 [ 0.,  1.,  1.,  1.,  0.,  1.,  0.,  0.,  0.,  0.]]

你可能感兴趣的:(文本分类方法总结)