Advertisement

NLP入门——天池新闻文本分类(3)基于机器学习的文本分类

阅读量:

NLP入门——天池新闻文本分类(3)基于机器学习的文本分类

    • 基于机器学习的文本分类

      • 学习目标
      • 机器学习模型
    • 文本表示方法

      • One-hot编码
      • Bag of Words
      • N-gram
      • TF-IDF
    • 基于机器学习的文本分类

      • Count Vecters + RidgeClassifier
      • TF-IDF + RidgeClassifier
      • 本章小结
    • 本章作业

基于机器学习的文本分类

这一次任务中会使用机器学习的模型来进行文本分类。机器学习的模型十分丰富,并且包括很多个分支。本次将使用一些传统机器学习进行文本分类。

学习目标

  1. 学会TF-IDF的原理和使用
  2. 使用sklearn的机器学习模型来进行文本分类

机器学习模型

机器学习中的分类模型有很多种,常见的分类器有K近邻决策树随机森林支撑向量机朴素贝叶斯逻辑回归等等,本章中我们会用到RidgeClassifier

文本表示方法

机器学习算法的训练过程中,如果给定N 个样本,每个样本有M 个特征,这样就组成了N*M 的样本矩阵然后完成算法的训练和预测。同样的在计算机视觉中会将图片像素看作特征,每张图就相当于hight * width * 3 的特征图,一个三维矩阵。
但是由于在自然语言领域中,文本长度通常是不定的。将文本表示为计算机可以运算的数字或向量特征的方法称为词嵌入(Word Embedding)方法。词嵌入会将不定长文本转换到定长特征空间中,是文本分类的第一步。

One-hot编码

One-hot编码将句子中每个单词用一个离散向量表示。具体的是将所有句子中出现的单词/词编码一个索引,然后根据索引进行赋值。

复制代码
    句子1: 我 爱 北 京 天 安 门
    句子2: 我 喜 欢 上 海

先根据所有句子的字确定索引:

复制代码
    {
    	'我': 1, '爱': 2, '北': 3, '京': 4, '天': 5,
    	'安': 6, '门': 7, '喜': 8, '欢': 9, '上': 10, '海': 11
    }

一共包括11个字,因此每个字都转换成了一个11维度的稀疏向量:

复制代码
    我:[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    爱:[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    ...
    海:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]

Bag of Words

Bag of Words(词袋表示),也称为Count Vectors,每个文档的字/词可以使用他出现的次数进行表示。
如上述两个句子直接统计每个字出现次数,并将每个句子对应索引位置处赋值为词频:

复制代码
    句子1:我 爱 北 京 天 安 门
    转换为 [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
    句子2:我 喜 欢 上 海
    转换为 [1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]

可以使用sklearn中的CountVectorizer来实现这一个转换:

复制代码
    from sklearn.feature_extraction.text import CountVectorizer
    corpus = [
    	'This is the first document.',
    	'This document is the second document.',
    	'And this is the third one.',
    	'Is this the first document?',
    ]
    vectorizer = CountVectorizer()
    vectorizer.fit_transform(corpus).toarray()
    # 输出
    array([[0, 1, 1, 1, 0, 0, 1, 0, 1],
       [0, 2, 0, 1, 0, 1, 1, 0, 1],
       [1, 0, 0, 1, 1, 0, 1, 1, 1],
       [0, 1, 1, 1, 0, 0, 1, 0, 1]], dtype=int64)

N-gram

N-gram也是统计单词词频,但是在语料库中加入了相邻单词组成的词语。如当N取值为2时,上述句子1和句子2就变为:

复制代码
    句句⼦子1:我爱 爱北 北京 京天 天安 安门
    句句⼦子2:我喜 喜欢 欢上 上海

TF-IDF

TF-IDF分数是由两部分组成:第一部分是词语频率(Term Frequency),第二部分是逆文档频率(Inverse Document Frequency)。
字词的重要性会随着他在文件中出现次数成正比增加,但是会随着他在语料库中出现的频率中出现的频率成反比下降。

  1. TF
    TF表示关键字在文档中出现的频率。tf_{ij}表示单词i在第j个文件中的词频,n_{i,j}是该词出现在文件d_j中的次数。母是文件中单词出现次数综合。
    tf_{ij}=\frac{n_{i,j}}{\sum_kn_{k,j}}
    即:TF_w=\frac{在某一类中词条w出现的次数}{该类中所有的词条数目}

  2. IDF
    IDF是逆向文件频率。由总文件数目初一包含盖茨与的文件的数目,如果包含该词条的文档越少,IDF越大,则说明词条有很好的类别区分能力。idf_i=log_2\frac{|D|}{|{j:t_i\in{d_j}}|}
    |D|是语料库中文件总数,|{j:t_i\in{d_j}}|表示包含该词语t_i的文件数目,即:
    IDF=log_2(\frac{语料库的文档总数}{包含该词条w的文档数+1})<分母+1的原因是避免分母为0>
    最后:
    TF-IDF=TF*IDF

基于机器学习的文本分类

我们对比不痛文本表示的算法的精度,通过构建验集计算F1分数

Count Vecters + RidgeClassifier

复制代码
    import pandas as pd
    from sklearn.feature_extraction.text import CountVectorizer
    from sklearn.linear_model import RidgeClassifier
    from sklearn.metrics import f1_score
    train_df = pd.read_csv('../input/train_set.csv', sep='\t', nrows=15000)
    
    vectorizer = CountVectorizer(max_features=3000)
    train_test = vectorizer.fit_transform(train_df['text'])
    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.74

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('../input/train_set.csv', sep='\t', nrows=15000)
    tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
    train_test = tfidf.fit_transform(train_df['text'])
    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.87

本章小结

本章使用了机器学习算法进行文本分类,并将Count VectorsTF-IDF Vectors进行了对比

本章作业

  1. 尝试改变TF-IDF的参数,并验证精度
    sklearn库中TfidfVectorizer的几个重要参数如下:
Column 1 Column 2
ngram_range 元组(min_n,max_n)的形式。表示提取n-grams的上下界。默认值为(1,1),表示提取词语的时候在范围min\_n\le n \le max\_n长度内的词语都会提取
max_df 浮点或者整形。表示最大文档频率,当是浮点数时,大于词文档频率的单词会被忽略;当是整形时,表示最大出现在多少个文档中,高于的忽略
max_features 整形。最大的特征词数,取词频最高的max_features个单词
复制代码
    from sklearn.feature_extraction.text import TfidfVectorizer
    from sklearn.metrics import accuracy_score
    train_df = pd.read_csv("./train_set.csv", sep='\t', nrows=15000)
    train_test = vectorizer.fit_transform(train_df['text'])
    for df in [0.75,0.77,0.78, 0.79,0.8]:
    tfidf = TfidfVectorizer(ngram_range=(1, 3), max_df=df, max_features = 7000)
    train_test = tfidf.fit_transform(train_df['text'])
    
    clf =RidgeClassifier()
    clf.fit(train_test[:10000], train_df['label'].values[:10000])
    
    val_pred  = clf.predict(train_test[10000:])
    print('df:{}'.format(df), f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
    print(accuracy_score(train_df['label'].values[10000:], val_pred))
复制代码
    # 输出
    df:0.77 0.8931458491540146
    0.9158
    df:0.78 0.8919163760078824
    0.9154
    df:0.79 0.8923133935002019
    0.9158
    df:0.8 0.8937502578052472
    0.9162

2.使用其它模型,完成训练验证
使用svm训练结果

复制代码
    import pandas as pd
    from sklearn.model_selection import KFold
    from sklearn.model_selection import cross_val_score
    from sklearn.feature_extraction.text import TfidfVectorizer
    from sklearn import svm
    
    train_df = pd.read_csv("./train_set.csv", sep='\t', nrows=15000)
    tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
    train_test = tfidf.fit_transform(train_df['text'])
    
    mean=[]
    std=[]
    kfold=KFold(n_splits=10,random_state=22)
    C=[0.9,1.0]
    gamma=[0.1,0.2]
    kernel=['linear','rbf']
    for i in C:
       for j in gamma:
       for k in kernel:
           result=cross_val_score(svm.SVC(kernel=k,C=i,gamma=j),train_test[:10000], train_df['label'].values[:10000],cv=kfold,scoring='accuracy')
           print(i,j,k,':')
           print(result.mean())
           mean.append(result.mean())
           print(result.std())
           std.append(result.std())
    Frame=pd.DataFrame({'mean':mean,'std':std})
复制代码
    # 输出
    0.9 0.1 linear :
    0.9000999999999999
    0.005204805471869247
    0.9 0.1 rbf :
    0.8669
    0.007803204469959768
    0.9 0.2 linear :
    0.9000999999999999
    0.005204805471869247
    0.9 0.2 rbf :
    0.8863
    0.00787464284904402
    1.0 0.1 linear :
    0.901
    0.004878524367060192
    1.0 0.1 rbf :
    0.8704000000000001
    0.007045565981523421
    1.0 0.2 linear :
    0.901
    0.004878524367060192
    1.0 0.2 rbf :
    0.889
    0.007127411872482192

全部评论 (0)

还没有任何评论哟~