TFIDF|用TFIDF词袋模型进行新闻分类


词袋不关注词的先后顺序---词袋模型(bow--一元模型)bag ofwords
二元模型
n-gram

# 创建输出目录保存训练好的模型 import os#对文件和目录进行操作 output_dir = u'output' if not os.path.exists(output_dir): os.mkdir(output_dir)

加载数据
import numpy as np#一个数据分析处理数据的常见的库,它提供的数据结构比 Python 自身的更高效 import pandas as pd

1.Pandas 是基于 NumPy 的一个开源 Python 库,它被广泛用于快速分析数据,以及数据清洗和准备等工作。它的名字来源是由“ Panel data”(面板数据,一个计量经济学名词)两个单词拼成的。简单地说,你可以把 Pandas 看作是 Python 版的 Excel。
2. Pandas能很好地处理来自各种不同来源的数据,比如 Excel 表格、CSV 文件、SQL 数据库,甚至还能处理存储在网页上的数据。
3. Pandas基于Numpy,常常与Numpy、matplotlib一起使用。
4. Pandas库的两个主要数据结构:
Series:一维
DataFrame:多维
python list 列表保存的是对象的指针,比如 [0,1,2] 需要保存 3 个指针和 3 个整数的对象,这样就很浪费内存了。
Numpy 是储存在一个连续的内存块中,节约了计算资源。
# 查看训练数据 train_data = https://www.it610.com/article/pd.read_csv('sohu_train.txt', sep='\t', header=None, dtype=np.str_, encoding='utf8',error_bad_lines=False, delimiter="\t", names=[u'频道', u'文章']) train_data.head()

TFIDF|用TFIDF词袋模型进行新闻分类
文章图片


# 载入停用词 stopwords = set() with open('stopwords.txt', 'r',encoding='utf8') as infile: for line in infile: line = line.rstrip('\n') if line: stopwords.add(line.lower())

计算每个文章的tfidf特征
import jieba from sklearn.feature_extraction.text import TfidfVectorizer

min_df去掉df值小的词这样的词一般是非常专业的名词或者是生僻词是噪音
max_df 去掉df值很大的词这样词是常用词 去掉不要
tfidf = TfidfVectorizer(tokenizer=jieba.lcut, stop_words=stopwords, min_df=50, max_df=0.3)#使用TfidfVectorizer实例化 x = tfidf.fit_transform(train_data[u'文章'])

·输出结果
Building prefix dict from the default dictionary ... Loading model from cache C:\Users\10248\AppData\Local\Temp\jieba.cache Loading model cost 0.550 seconds. Prefix dict has been built successfully. E:\ANACODAN\lib\site-packages\sklearn\feature_extraction\text.py:388: UserWarning: Your stop_words may be inconsistent with your preprocessing. Tokenizing the stop words generated tokens ['&', ',', '.', '; ', 'e', 'g', 'nbsp', '—', '\u3000', '傥', '兼', '前', '唷', '啪', '啷', '喔', '始', '漫', '然', '特', '竟', '若果', '莫', '见', '设', '说', '达', '非'] not in stop_words. warnings.warn('Your stop_words may be inconsistent with '

print(u'词表大小: {}'.format(len(tfidf.vocabulary_)))

词表大小: 14516

训练分类器 编码目标变量因为咱们的标签是字符串sklearn只接受数值
from sklearn.preprocessing import LabelEncoder#LabelEncoder:将类别数据数字化 y_encoder = LabelEncoder() y = y_encoder.fit_transform(train_data[u'频道'])#将类别转换成0,1,2,3,4,5,6,7,8,9... y[:10]

·输出结果
array([3, 3, 3, 3, 3, 3, 3, 3, 3, 3])

编码X变量
x = tfidf.transform(train_data[u'文章'])
# 划分训练测试数据 from sklearn.model_selection import train_test_split#分割数据集 # 根据y分层抽样,测试数据占20% #因为现在数据量很大此时采用对下标进行分割 train_idx, test_idx = train_test_split(range(len(y)), test_size=0.2, stratify=y) train_x = x[train_idx, :]#训练集 train_y = y[train_idx] test_x = x[test_idx, :]#测试集 test_y = y[test_idx]

训练逻辑回归模型 我们是12分类属于多分类
常用参数说明
penalty: 正则项类型,l1还是l2
C: 正则项惩罚系数的倒数,越大则惩罚越小
fit_intercept: 是否拟合常数项
max_iter: 最大迭代次数
multi_class: 以何种方式训练多分类模型
ovr = 对每个标签训练二分类模型
multinomial ovo = 直接训练多分类模型,仅当solver={newton-cg, sag, lbfgs}时支持
solver: 用哪种方法求解,可选有{liblinear, newton-cg, sag, lbfgs}
小数据liblinear比较好,大数据量sag更快
多分类问题,liblinear只支持ovr模式,其他支持ovr和multinomial
liblinear支持l1正则,其他只支持l2正则
from sklearn.linear_model import LogisticRegression#引入逻辑回归 model = LogisticRegression(multi_class='multinomial', solver='lbfgs')#solver='lbfgs':求解方式 model.fit(train_x, train_y)

·输出结果
E:\ANACODAN\lib\site-packages\sklearn\linear_model\_logistic.py:763: ConvergenceWarning: lbfgs failed to converge (status=1): STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.Increase the number of iterations (max_iter) or scale the data as shown in: https://scikit-learn.org/stable/modules/preprocessing.html Please also refer to the documentation for alternative solver options: https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression n_iter_i = _check_optimize_result(

LogisticRegression(multi_class='multinomial')

模型效果评估
from sklearn.metrics import confusion_matrix, precision_recall_fscore_support # 在测试集上计算模型的表现 test_y_pred = model.predict(test_x) # 计算混淆矩阵 pd.DataFrame(confusion_matrix(test_y, test_y_pred), columns=y_encoder.classes_, index=y_encoder.classes_)

·输出结果
体育 健康 女人 娱乐 房地产 教育 文化 新闻 旅游 汽车 科技 财经 体育 193 1 0 1 0 0 3 2 0 0 0 0 健康 0 165 9 0 0 4 0 7 3 0 4 8 女人 1 5 167 4 0 0 13 5 3 0 1 1 娱乐 0 1 9 164 0 5 17 2 0 0 1 1 房地产 0 1 4 0 180 0 0 3 0 0 1 11 教育 0 0 3 2 0 185 2 6 1 0 1 0 文化 0 3 13 17 0 1 153 8 2 1 2 0 新闻 1 4 6 5 1 12 4 124 5 2 11 25 旅游 0 2 8 0 6 1 8 8 163 0 1 3 汽车 1 1 3 0 0 0 0 4 2 182 1 6 科技 0 1 0 0 0 2 2 12 5 1 164 13 财经 1 4 3 0 12 0 4 19 2 4 11 140

# 计算各项评价指标 def eval_model(y_true, y_pred, labels): # 计算每个分类的Precision, Recall, f1, support p, r, f1, s = precision_recall_fscore_support(y_true, y_pred) # 计算总体的平均Precision, Recall, f1, support tot_p = np.average(p, weights=s) tot_r = np.average(r, weights=s) tot_f1 = np.average(f1, weights=s) tot_s = np.sum(s) res1 = pd.DataFrame({ u'Label': labels, u'Precision': p, u'Recall': r, u'F1': f1, u'Support': s }) res2 = pd.DataFrame({ u'Label': [u'总体'], u'Precision': [tot_p], u'Recall': [tot_r], u'F1': [tot_f1], u'Support': [tot_s] }) res2.index = [999] res = pd.concat([res1, res2]) return res[[u'Label', u'Precision', u'Recall', u'F1', u'Support']]

·输出结果
eval_model(test_y, test_y_pred, y_encoder.classes_)

Label Precision Recall F1 Support 0 体育 0.979695 0.965 0.972292 200 1 健康 0.877660 0.825 0.850515 200 2 女人 0.742222 0.835 0.785882 200 3 娱乐 0.849741 0.820 0.834606 200 4 房地产 0.904523 0.900 0.902256 200 5 教育 0.880952 0.925 0.902439 200 6 文化 0.742718 0.765 0.753695 200 7 新闻 0.620000 0.620 0.620000 200 8 旅游 0.876344 0.815 0.844560 200 9 汽车 0.957895 0.910 0.933333 200 10 科技 0.828283 0.820 0.824121 200 11 财经 0.673077 0.700 0.686275 200 999 总体 0.827759 0.825 0.825831 2400

模型保存
# 保存模型到文件pip install dill #注意我们要把tfidf特征提取模型保存标签转换模型预测模型 !pip install dill import dill import pickle model_file = os.path.join(output_dir, u'model.pkl') with open(model_file, 'wb') as outfile: dill.dump({ 'y_encoder': y_encoder, 'tfidf': tfidf, 'lr': model }, outfile)

·输出结果
Requirement already satisfied: dill in e:\anacodan\lib\site-packages (0.3.4)

测试模型,对新文档预测
# 加载新文档数据 new_data = https://www.it610.com/article/pd.read_csv('sohu_test.txt', sep='\t', header=None, dtype=np.str_, encoding='utf8',error_bad_lines=False, delimiter="\t", names=[u'频道', u'文章']) new_data.head()

TFIDF|用TFIDF词袋模型进行新闻分类
文章图片


# 加载模型 import pickle model_file = os.path.join(output_dir, u'model.pkl') with open(model_file, 'rb') as infile: model = pickle.load(infile)

# 对新文档预测(这里只对前10篇预测) # 1. 转化为词袋表示 new_x = model['tfidf'].transform(new_data[u'文章'][:50])

·输出结果
E:\ANACODAN\lib\site-packages\sklearn\feature_extraction\text.py:388: UserWarning: Your stop_words may be inconsistent with your preprocessing. Tokenizing the stop words generated tokens ['&', ',', '.', '; ', 'e', 'g', 'nbsp', '—', '\u3000', '傥', '兼', '前', '唷', '啪', '啷', '喔', '始', '漫', '然', '特', '竟', '若果', '莫', '见', '设', '说', '达', '非'] not in stop_words. warnings.warn('Your stop_words may be inconsistent with '

# 2. 预测类别 new_y_pred = model['lr'].predict(new_x) new_y_pred

·输出结果
array([3, 0, 3, 3, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3])

# 3. 解释类别 pd.DataFrame({u'预测频道': model['y_encoder'].inverse_transform(new_y_pred), u'实际频道': new_data[u'频道'][:50]})

·输出结果
预测频道 实际频道 0 娱乐 娱乐 1 体育 娱乐 2 娱乐 娱乐 3 娱乐 娱乐 4 教育 娱乐 5 娱乐 娱乐 6 娱乐 娱乐 7 娱乐 娱乐 8 娱乐 娱乐 9 娱乐 娱乐 10 娱乐 娱乐 11 娱乐 娱乐 12 娱乐 娱乐 13 娱乐 娱乐 14 娱乐 娱乐 15 娱乐 娱乐 16 娱乐 娱乐 17 娱乐 娱乐 18 娱乐 娱乐 19 娱乐 娱乐 20 娱乐 娱乐 21 娱乐 娱乐 22 娱乐 娱乐 23 娱乐 娱乐 24 娱乐 娱乐 25 娱乐 娱乐 26 娱乐 娱乐 27 娱乐 娱乐 28 娱乐 娱乐 29 娱乐 娱乐 30 娱乐 娱乐 31 娱乐 娱乐 32 娱乐 娱乐 33 娱乐 娱乐 34 娱乐 娱乐 35 娱乐 娱乐 36 娱乐 娱乐 37 娱乐 娱乐 38 娱乐 娱乐 39 娱乐 娱乐 40 娱乐 娱乐 41 娱乐 娱乐 42 娱乐 娱乐 43 娱乐 娱乐 44 娱乐 娱乐 45 娱乐 娱乐 46 娱乐 娱乐 47 娱乐 娱乐 48 娱乐 娱乐 49 娱乐 娱乐

主函数,调用模型对新闻进行预测
# 加载模型 import pickle import os import numpy as np import pandas as pdoutput_dir = u'output' if not os.path.exists(output_dir): os.mkdir(output_dir)model_file = os.path.join(output_dir, u'model.pkl') with open(model_file, 'rb') as infile: model = pickle.load(infile)oo = 1 while oo == 1: f = open('yuce.txt', 'w', encoding='utf8') f.write(input()) f.close() new1_data = https://www.it610.com/article/pd.read_csv('yuce.txt', sep='\t', header=None, dtype=np.str_, encoding='utf8', names=[u'文章']) new1_data.head() # 加载模型 import picklemodel_file = os.path.join(output_dir, u'model.pkl') with open(model_file, 'rb') as infile: model = pickle.load(infile) new1_x = model['tfidf'].transform(new1_data[u'文章']) # 2. 预测类别 new1_y_pred = model['lr'].predict(new1_x) pd.DataFrame({u'预测频道': model['y_encoder'].inverse_transform(new1_y_pred)}) print(pd.DataFrame({u'预测频道': model['y_encoder'].inverse_transform(new1_y_pred)})) with open(r'yuce.txt', 'a+', encoding='utf-8') as test: test.truncate(0)

【TFIDF|用TFIDF词袋模型进行新闻分类】

    推荐阅读