天天看点

python朴素贝叶斯调参_机器学习笔记(4) -- 文本分类实例(20Newgroups数据集)...

1. 问题定义

在这个项目中会采用20Newgroups的数据,这是在网上非常流行的对文本进行分类和聚类的数据集。数据集中的数据分为两部分,一部分是用来训练算法模型的数据,一部分是用来评估算法的新数据。网上还提供了3个数据集,这里采用了20new-bydate这个数据集进行项目研究。这个数据集是按照日期进行排序的,并去掉了部分重复数据和header,共包含18846个文档。

2.导入数据

这里使用scikit-learn的loadfiles导入文档数据,文档是按照不同的分类分目录来保存的,文件目录 名称即所属类别。

python朴素贝叶斯调参_机器学习笔记(4) -- 文本分类实例(20Newgroups数据集)...

在导入文档数据之前,要导入项目中所需的类库。

# 导入类库

from sklearn.datasets import load_files

from sklearn.feature_extraction.text import CountVectorizer

from sklearn.feature_extraction.text import TfidfVectorizer

from sklearn.linear_model import LogisticRegression

from sklearn.naive_bayes import MultinomialNB

from sklearn.neighbors import KNeighborsClassifier

from sklearn.svm import SVC

from sklearn.tree import DecisionTreeClassifier

from sklearn.metrics import classification_report

from sklearn.metrics import accuracy_score

from sklearn.model_selection import cross_val_score

from sklearn.model_selection import KFold

from sklearn.model_selection import GridSearchCV

from sklearn.ensemble import AdaBoostClassifier

from sklearn.ensemble import RandomForestClassifier

from matplotlib import pyplot as plt

import warnings

warnings.filterwarnings('ignore')

利用机器学习对文本进行分类,与对数值特征进行分类最大的区别是,对文本进行分类是要先提取文本特征,提取到的文本特征属性的个数是巨大的,会有超万个的特征属性。

3. 文本特征提取

文本数据属于非结构化的数据,一般要转换成结构化的数据才能够通过机器学习算法进行分类。常见的做法是将文本转换成“文档-词项矩阵”,矩阵中的元素可以使用词频或TF-IDF值等。

TF-IDF值是一种用于信息检索与数据挖掘的常用加权技术。TF的意思是词频(Term Frequency),IDF的意思是逆向文件频率(Inverse Document Frequency)。TF-IDF的主要思想是:如果某一个词或短语在一篇文章中出现的频率高,并且在其他文章中很少出现,则认为此词或短语具有很好的类别区分能力,时适合用来分类。TF-IDF实际上是TF*IDF。

IDF的主要思想是:如果包含词条t的文档越少,也就是n越小,IDF越大,则说明词条t具有很好的类别区分能力,如果某一类文档C中包含词条t的文档数为m,而其他类包含t的文档总数为k,显然所有包含t的文档数n = m + k,当m打的时候,n也大,按照IDF公式得到的IDF的值小,这说明该词条t的类别区分能力不强。但是实际上,如果一个词条在一个类的文档中频繁出现,这说明该词条能够很好地代表这个类的文本特征,这样的词条应该被赋予较高的权重,并将其作为该类文本的特征词,以区别于其他类文档。这就是IDF的不足之处,在一份给定的文件里,TF指的是某一个给定的词语在该文件中出现的频率,这是对词数(Term Count)的归一化,乙方他偏向长的文件。IDF是一个词语普遍重要性的度量,某一特定词语的IDF,可以由总文件数目除以包含该词语的文件的数目,再将得到的商取对数得到。

在scikit-learn中提供了词频和TF-IDF来进行文本特征提取的实现,分别是CountVectorizer和TfidTransformer。下面对训练数据集分别进行词频和TF-IDF的计算。

# 数据准备与理解

# 计算词频

count_vect = CountVectorizer(stop_words= 'english',decode_error ='ignore')

X_train_counts = count_vect.fit_transform(dataset_train.data)

# 查看数据维度

print(X_train_counts.shape)

词频统计结果:

python朴素贝叶斯调参_机器学习笔记(4) -- 文本分类实例(20Newgroups数据集)...

然后计算TF-IDF:

# 计算TF-IDF

tf_transformer = TfidfVectorizer(stop_words='english',decode_error='ignore')

X_train_counts_tf = tf_transformer.fit_transform(dataset_train.data)

# 查看数据维度

print(X_train_counts_tf.shape)

TF-IDF的计算结果:

python朴素贝叶斯调参_机器学习笔记(4) -- 文本分类实例(20Newgroups数据集)...

这里通过两种方法进行了文本特征的提取,并且查看了数据维度,得到的数据维度还是非常巨大的。

4. 评估算法

通过简单地查看数据维度,不能确定那个算法对和这个问题比较有效。下面将采用10折交叉验证的方式来比较算法的准确度,一遍找到处理问题最有效的两三种算法,然后进行下一步的处理。

# 设置评估算法的基准

num_folds = 10

seed = 7

scoring = 'accuracy'

接下来将会利用提取到的文本特征TF-IDF来对算法进行审查,审查的算法如下:

线性算法:逻辑回归(LR)

非线性算法:分类与回归树(CART)、支持向量机(SVM)、朴素贝叶斯分类器(MNB)和K近邻(KNN)。

# 评估算法

# 生成算法模型

models = {}

models['LR'] = LogisticRegression()

models['SVM'] = SVC()

models['CART'] = DecisionTreeClassifier()

models['MNB'] = MultinomialNB()

models['KNN'] = KNeighborsClassifier()

所有的算法使用默认参数,比较算法的准确度和标准方差,以便从中选择两三种可以进一步进行研究的算法。

# 比较算法

results = []

for key in models:

kfold = KFold(n_splits= num_folds,random_state= seed)

cv_results = cross_val_score(models[key],X_train_counts_tf,dataset_train.target,cv = kfold,scoring=scoring)

results.append(cv_results)

print('%s :%f(%f)'%(key,cv_results.mean(),cv_results.std()))

执行结果显示,逻辑回归(LR)具有最后的准确度,朴素贝叶斯分类器(MNB)和K近邻也值得进一步研究。

python朴素贝叶斯调参_机器学习笔记(4) -- 文本分类实例(20Newgroups数据集)...

接下来看一下算法每次执行结果的分布情况。

python朴素贝叶斯调参_机器学习笔记(4) -- 文本分类实例(20Newgroups数据集)...

5.算法调参

通过上面的分析,逻辑回归(LR)和朴素贝叶斯分类器(MNB)算法值得进一步优化。下面对这两个算法的参数进行调参,进一步提高算法的准确度。

5.1 逻辑回归调参

在逻辑回归中的超参数是C。C是目标的约束函数,C值越小则正则化强度越大。对C进行设定一定数量的值,如果临界值是最优参数,重复这个步骤,直到找到最优值。

# 调参LR

param_grid = {}

param_grid['C'] = [0.1,5,13,15]

model = LogisticRegression()

kfold = KFold(n_splits=num_folds,random_state=seed)

grid = GridSearchCV(estimator=model,param_grid = param_grid, scoring = scoring,cv=kfold)

grid_result = grid.fit(X=X_train_counts_tf,y=dataset_train.target)

print('最优:%s 使用%s'%(grid_result.best_score_,grid_result.best_params_))

可以看到C的最优参数是15。

python朴素贝叶斯调参_机器学习笔记(4) -- 文本分类实例(20Newgroups数据集)...

5.2 朴素贝叶斯分类器调参

通过对逻辑回归调参,准确度提升到大概0.92,提升还是比较大的。朴素贝叶斯分类器有一个alpha参数,该参数是一个平滑参数,默认值为1.0。我们也可以对这个参数进行调参,以提高算法的准确度。

# 调参 MNB

param_grid ={}

param_grid['alpha'] = [0.001,0.01,0.1,1.5]

model = MultinomialNB()

kfold = KFold(n_splits=num_folds,random_state=seed)

grid = GridSearchCV(estimator= model, param_grid = param_grid, scoring=scoring, cv=kfold)

grid_result = grid.fit(X = X_train_counts_tf, y = dataset_train.target)

print('最优:%s 使用%s'%(grid_result.best_score_,grid_result.best_params_))

同样,通过多次调整param_grid,得到的朴素贝叶斯分类器的alpha参数的最优值是0.01。

python朴素贝叶斯调参_机器学习笔记(4) -- 文本分类实例(20Newgroups数据集)...

通过调参发现,逻辑回归在C = 15 是具有最好的准确度。接下来进行审查集成算法。

6. 集成算法

除了调参,提高算法准确度的方法是使用集成算法。下面对两种集成算法进行比较,看看能否进一步提高模型的准确度。

随机森林(RF)

AdaBoost(AB)

# 集成算法

ensembles = {}

ensembles['RF'] = RandomForestClassifier()

ensembles['AB'] = AdaBoostClassifier()

# 比较集成算法

results = []

for key in ensembles:

kfold = KFold(n_splits= num_folds,random_state= seed)

cv_results = cross_val_score(ensembles[key],X_train_counts_tf,dataset_train.target,cv = kfold,scoring = scoring)

results.append(cv_results)

print('%s : %f(%f)'%(key,cv_results.mean(),cv_results.std()))

评估结果:

python朴素贝叶斯调参_机器学习笔记(4) -- 文本分类实例(20Newgroups数据集)...

7. 集成算法调参

通过对集成算法的分析,发现随机森林算法具有较高的准确度和非常稳定的数据分布,非常值得进行进一步的研究。下面通过调参对随机森林算法进行优化。随机森林有一个很重要的参数n_estimators,下面对n_estimators进行调参优化,争取找到最优解。

# 调参RF

param_grid = {}

param_grid['n_estimators'] = [10,100,150,200]

model = RandomForestClassifier()

kfold = KFold(n_splits=num_folds,random_state= seed)

grid = GridSearchCV(estimator=model,param_grid = param_grid, scoring = scoring,cv = kfold)

grid_result = grid.fit(X =X_train_counts_tf,y = dataset_train.target)

print('最优:%s 使用%s'%(grid_result.best_score_,grid_result.best_params_))

调参之后的最优结果如下:

python朴素贝叶斯调参_机器学习笔记(4) -- 文本分类实例(20Newgroups数据集)...

8. 确定最终模型

通过对算法的比较和调参发现,逻辑回归算法具有最高的准确度,因此使用逻辑回归算法生成算法模型。接下来会利用评估数据集对生成的模型进行验证,以确认模型的准确度。需要注意的是,为了保持数据特征的一致性,对新数据进行文本特征提取是应进行特征扩充,下面使用之前生成的tf_transformer的transform方法来处理评估数据集。

# 生成模型

model = LogisticRegression(C = 15)

model.fit(X_train_counts_tf,dataset_train.target)

X_test_counts = tf_transformer.transform(dataset_test.data)

predictions = model.predict(X_test_counts)

print(accuracy_score(dataset_test.target, predictions))

print(classification_report(dataset_test.target, predictions))

从结果可以看到,准确度大概达到了85%,与期待的结果比较一致。执行结果:

python朴素贝叶斯调参_机器学习笔记(4) -- 文本分类实例(20Newgroups数据集)...

参考从书:《机器学习Python实践》 魏贞原