# 在实际应用中还有一类问题比较重要,那就是文本分类。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
'''
在这个项目中会采用20Newgroups的数据(http:/qwone.com/-jason/20Newsgroups/),
这是网上非常流行的对文本进行分类和聚类的数据集。数据集中的数据分为两部分,
一部分是用来训练算法模型的数据,一部分是用来评估算法的新数据。
网站上还提供了3个数据集,这里采用20news-bydate这个数据集进行项目研究。
这个数据集是按照日期进行排序的,并去掉了部分重复数据和header,共包含18846个文档。
'''
'''
这里使用scikit-learn的loadfiles导入文档数据,文档是按照不同的分类分目录来保存的,
文件目录名称即所属类别,文件目录结构如图22-1所示。
'''
# 1) 导入数据
categories = ['alt.atheism',
'rec.sport.hockey',
'comp.graphics',
'sci.crypt',
'comp.os.ms-windows.misc',
'sci.electronics',
'comp.sys.ibm.pc.hardware',
'sci.med',
'comp.sys.mac.hardware',
'sci.space',
'comp.windows.x',
'soc.religion.christian',
'misc.forsale',
'talk.politics.guns',
'rec.autos'
'talk.politics.mideast',
'rec.motorcycles',
'talk.politics.misc',
'rec.sport.baseball',
'talk.religion.misc']
# 导入训练数据
train_path = '20news-bydate-train'
dataset_train = load_files(container_path=train_path, categories=categories)
# 导入评估数据
test_path = '20news-bydate-test'
dataset_test = load_files(container_path=test_path, categories=categories)
# 2)数据准备与理解
'''
利用机器学习对文本进行分类,与对数值特征进行分类最大的区别是,
对文本进行分类时要先提取文本特征,相对于之前的项目来说,
提取到的文本特征属性的个数是巨大的,会有超过万个的特征属性,甚至会超过10万个。
'''
'''
在scikit-learn中提供了词频和TF-IDF来进行文本特征提取的实现,
分别是Count Vectorizer 和TfidfTransformer。下面对训练数据集分别进行词频和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) #(10156,122402)
# 计算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) # (10156,122402)
'''
这里通过两种方法进行了文本特征的提取,并且查看了数据维度,
得到的数据维度还是非常巨大的。在后续的项目中,将使用TF-IDF进行分类模型的训练。
因为,TF-IDF的数据维度巨大,并且自用提取的特征数据,进一步对数据进行分析的意义不大,
因此只简单地查看数据维度的信息。接下来将进行算法评估。
'''
# 设置评估算法的基准
num_folds = 10
seed = 7
scoring = 'accuracy'
# 3)评估算法
'''
接下来将会利用提取到的文本特征TF-IDF来对算法进行审查,
所有的算法使用默认参数,比较算法模型的准确度和标准方差,
以便从中选择两三种可以进一步进行研究的算法。代码如下:
'''
# 生成算法模型
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近邻(KNN)也值得进一步的研究。执行结果如下:
LR:0.901636(0.010638)
SVM:0.047658(0.004797)
CART:0.662171(0.015739)
MNB:0.880760(0.006831)
KNN:0.797163(0.011413)
'''
# 箱线图比较算法
'''
执行结果如图22-2所示,从图中可以看到,朴素贝叶斯分类器的数据离散程度比较好,
逻辑回归的偏度较大。算法结果的离散程度能够反应算法对数据的适用情况,
所以对逻辑回归和朴素贝叶斯分类器进行进一步的研究,实行算法调参。
'''
fig = plt.figure()
fig.suptitle('Algorithm Comparision')
ax = fig.add_subplot(111)
plt.boxplot(results)
ax.set_xticklabels(models.keys())
plt.show()
# 4)算法调参
# 调参LR
'''
在逻辑回归中的超参数是C。C是目标的约束函数,C值越小则正则化强度越大。
对C进行调参,每次给C设定一定数量的值,如果临界值是最优参数,重复这个步骤,直到找到最优值。
代码如下:
'''
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_))
# 最优:0.925167388736使用{'C':13}
# 调参MNB
'''
通过对逻辑回归调参,准确度提升到大概0.92,提升还是比较大的。
朴素贝叶斯分类器有一个alpha参数,该参数是一个平滑参数,默认值为1.0。
我们也可以对这个参数进行调参,以提高算法的准确度。代码如下:
'''
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_))
# 最优:0.916502560063使用{alpha':0.01}
# 5)集成算法
'''
除了调参,提高算法准确度的方法是使用集成算法。
'''
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()))
'''
RF:0.733162(0.015826)
AB:0.558684(0.011587)
'''
# 箱线图比较算法
fig = plt.figure()
fig.suptitle('Algorithm Comparision')
ax = fig.add_subplot(111)
plt.boxplot(results)
ax.set_xticklabels(ensembles.keys())
plt.show()
# 集成算法调参
# 调参RF
'''
通过对集成算法的分析,发现随机森林算法具有较高的准确度和非常稳定的数据分布,
非常值得进行进一步的研究。下面通过调参对随机森林算法进行优化。
随机森林有一个很重要的参数n estimators,下面对n_estimators 进行调参优化,争取找到最优解。
代码如下:
'''
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_))
# 最优:0.867467506892使用{'n estimators':150}
'''
通过对算法的比较和调参发现,逻辑回归算法具有最高的准确度,
因此使用逻辑回归算法生成算法模型。接下来会利用评估数据集对生成的模型进行验证,
以确认模型的准确度。需要注意的是,为了保持数据特征的一致性,
对新数据进行文本特征提取时应进行特征扩充,
下面使用之前生成的tf_transformer的transform方法来处理评估数据集。
代码如下:
'''
# 6)生成模型
model = LogisticRegression(C=13)
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))
文本分类
最新推荐文章于 2022-07-09 22:47:33 发布