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

词袋  不关注词的先后顺序---词袋模型(bow--一元模型)  bag of  words 
二元模型
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 = 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词袋模型进行新闻分类_第1张图片

# 载入停用词
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 = 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词袋模型进行新闻分类_第2张图片

# 加载模型
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 pd

output_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 = pd.read_csv('yuce.txt', sep='\t', header=None, dtype=np.str_, encoding='utf8', names=[u'文章'])
    new1_data.head()
    # 加载模型
    import pickle

    model_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,分类,数据挖掘,人工智能)