【自然语言处理】词袋模型在文本分类中的用法

词袋模型在文本分类中的用法

1.加载数据

20 Newsgroups:数据被组织成 20 个不同的新闻组,每个新闻组对应一个不同的主题。一些新闻组彼此非常密切相关(例如 comp.sys.ibm.pc.hardware / comp.sys.mac.hardware),而其他新闻组则非常不相关(例如 misc.forsale / soc.religion.christian)。以下是 20 个新闻组的列表,按主题划分(或多或少):

【自然语言处理】词袋模型在文本分类中的用法_第1张图片
数据集:下载地址

# 加载训练集、测试集
from sklearn import datasets
twenty_train = datasets.load_files("20news-bydate/20news-bydate-train")
twenty_test = datasets.load_files("20news-bydate/20news-bydate-test")

sklearn.datasets.load_files(container_path, description=None, categories=None, load_content=True, shuffle=True, encoding=None, decode_error=‘strict’, random_state=0)

  • container_path:container_folder 的路径;
  • load_content = True:是否把文件中的内容加载到内存;
  • encoding = None:编码方式。当前文本文件的编码方式一般为 utf-8,如果不指明编码方式(encoding=None),那么文件内容将会按照 bytes 处理,而不是 unicode 处理。

返回值:Bunch,Dictionary-like object。主要属性包括:

  • data:原始数据;
  • filenames:每个文件的名字;
  • target:类别标签(从 0 0 0 开始的整数索引);
  • target_names:类别标签的具体含义(由子文件夹的名字 category_1_folder 等决定)。

2.文本表示

将文本文件变成数字的特征表示,这里主要是利用词袋模型。

2.1 BOW

使用 CountVectorizer 构建词频向量。CountVectorizer 支持单词或者连续字符的 N-gram 模型的计数,利用 scipy.sparse 矩阵只在内存中保存特征向量中非 0 0 0 元素位置以节省内存。

from sklearn.feature_extraction.text import CountVectorizer
count_vect = CountVectorizer(stop_words="english", decode_error='ignore')  # 创建词频转换器
X_train_counts = count_vect.fit_transform(twenty_train.data)  # 转换训练集
print(X_train_counts.shape)
(11314, 129782)

2.2 TF-IDF

用 TfidfTransformer 将词频向量转为 TF-IDF 形式。

from sklearn.feature_extraction.text import TfidfTransformer
tfidf_transformer = TfidfTransformer()
X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)
print(X_train_tfidf.shape)
(11314, 129782)

3.文本分类

3.1 正常流程

离散型朴素贝叶斯 MultinomialNB,朴素贝叶斯模型在多项分布假设下的实现,适用于多分类场景。

from sklearn.naive_bayes import MultinomialNB
clf = MultinomialNB()
clf.fit(X_train_tfidf, twenty_train.target)
docs_new = ['God is love', 'OpenGL on the GPU is fast']
X_new_counts = count_vect.transform(docs_new)  # 计算词频
X_new_tfidf = tfidf_transformer.transform(X_new_counts)  # 计算 TF-IDF
y_pred = clf.predict(X_new_tfidf)
for doc, category in zip(docs_new, y_pred):  # category是数字
    print(("%r => %s")%(doc, twenty_train.target_names[category]))

在这里插入图片描述

3.2 管道流水

使用管道后,测试集不用一步步重复训练集的预处理,直接管道处理了。

from sklearn.pipeline import Pipeline
text_clf = Pipeline([('vect', CountVectorizer(stop_words="english", decode_error='ignore')),
                    ('tfidf', TfidfTransformer()),
                    ('clf', MultinomialNB())
                     ])
text_clf = text_clf.fit(twenty_train.data, twenty_train.target)  # 训练集
score = text_clf.score(twenty_test.data, twenty_test.target)  # 测试集
print(score)
0.8169144981412639

SVM,对于大型数据集,使用 LinearSVC 或 SGDClassifier。

from sklearn.linear_model import SGDClassifier
from sklearn import metrics
text_clf_2 = Pipeline([('vect', CountVectorizer(stop_words='english', decode_error='ignore')), # 去停用词
                      ('tfidf', TfidfTransformer()),
                      ('clf', SGDClassifier(loss='hinge', penalty='l2', alpha=1e-3, max_iter=100, random_state=42))
                       ])
text_clf_2.fit(twenty_train.data, twenty_train.target)
# text_clf_2.score(twenty_test.data, twenty_test.target)
y_pred = text_clf_2.predict(twenty_test.data)
acc = metrics.accuracy_score(twenty_test.target, y_pred)
print(acc)
0.8227562400424854

4.结果报告

各类别的精确度,召回率,F值等。

print(metrics.classification_report(twenty_test.target, y_pred, target_names=twenty_test.target_names))

【自然语言处理】词袋模型在文本分类中的用法_第2张图片

5.超参调优

5.1 网格搜索

  • CountVectorizer() 中的 n-gram
  • TfidfTransformer() 中的 use_idf
  • SGClassifier() 中的惩罚系数 alpha
from sklearn.model_selection import GridSearchCV
parameters = {
            'vect__ngram_range': [(1, 1), (1, 2)],
            'tfidf__use_idf': (True, False),
            'clf__alpha': (1e-2, 1e-3)
             }
gs_clf = GridSearchCV(text_clf_2, parameters, n_jobs=-1, cv=5)  # text_clf_2: SVC 的 Pipeline
grid_result = gs_clf.fit(twenty_train.data, twenty_train.target)
print("Best: %f \nusing %s" % (grid_result.best_score_, grid_result.best_params_))
Best: 0.906842 
using {'clf__alpha': 0.001, 'tfidf__use_idf': True, 'vect__ngram_range': (1, 2)}

5.2 随机搜索

随机搜索进行超参数优化。

from sklearn.model_selection import RandomizedSearchCV
parameters = {
            'vect__ngram_range': [(1, 1), (1, 2), (2, 2)],
            'tfidf__use_idf': (True, False),
            'clf__alpha': (1e-1, 1e-2, 1e-3, 1e-4, 1e-5)
             }
rs_clf = RandomizedSearchCV(text_clf_2, parameters, n_jobs=-1, cv=5)
rs_result = rs_clf.fit(twenty_train.data, twenty_train.target)
print("Best: %f \nusing %s" % (rs_result.best_score_, rs_result.best_params_))
Best: 0.927436 
using {'vect__ngram_range': (1, 2), 'tfidf__use_idf': True, 'clf__alpha': 1e-05}

已确定 TfidfTransformer 里的参数 use_idf=True 会更好。

5.3 网格搜索-增加超参数

增加参数:

  • CountVectorizer 里的 max_df:按 比例绝对数量 删除 d f超过 max_df 的词。
  • CountVectorizer里的 max_features:选择 tf 最大的 max_features 个特征。
  • TfidfTransformer里的 norm:数据标准化,{‘l1’, ‘l2’} or None, default=’l2’。
  • SGDClassifier里的 penalty:惩罚项。
  • SGDClassifier里的 n_iter:迭代次数。

重要的参数:

  • vect__max_df
  • vect__ngram_range
  • clf__alpha
  • clf__penalty
from sklearn.model_selection import GridSearchCV
from sklearn.linear_model import SGDClassifier
from sklearn.pipeline import Pipeline

text_clf_3 = Pipeline([
    ('vect', CountVectorizer(stop_words="english", decode_error='ignore')),
    ('tfidf', TfidfTransformer()),
    ('clf', SGDClassifier()), 
]) 

parameters = {
    'vect__max_df': (0.5, 0.75, 1.0),
    'vect__max_features': (None, 10000, 50000,60000),
    'vect__ngram_range': [(1, 1), (1, 2),(2,2)],  
    'tfidf__norm': ('l1', 'l2'), 
    'clf__alpha': (0.0001, 0.00001, 0.000001,0.0000001),
    'clf__penalty': ('l2', 'elasticnet'),
    'clf__max_iter': (10, 50, 80),
}

gs_clf = GridSearchCV(text_clf_3, parameters, n_jobs = -1, cv=5)
grid_result = gs_clf.fit(twenty_train.data, twenty_train.target)
print("Best: %f \nusing %s" % (grid_result.best_score_, grid_result.best_params_))

计算的时间有点长,最好自己验证一下。

Best: 0.931766 
using {'vect__ngram_range': (1, 2), 
	   'clf__alpha': 1e-07, 
	   'vect__max_df': 0.75, 
	   'vect__max_features': None, 
	   'clf__n_iter': 50, 
	   'clf__penalty': 'elasticnet', 
	   'tfidf__norm': 'l1'
}

总结:当文本被向量化后,就可以将其看作是数字,按照常见的机器学习方法进行回归、分类、聚类、降维等任务。

你可能感兴趣的:(自然语言处理,自然语言处理,词袋模型,文本分类,TF-IDF)