基于NLP自然语言构建的文档自动分类系统(搜狐娱乐)—word2vec模型

开发环境 jupyter notebook

项目数据下载地址:https://download.csdn.net/download/wsp_1138886114/10612733
项目数据下载地址:https://download.csdn.net/download/wsp_1138886114/10612746

1 加载数据

import numpy as np
import pandas as pd

# 查看训练数据
train_data = pd.read_csv('data/sohu_train.txt', sep='\t', header=None, 
                         dtype=np.str_, encoding='utf8', names=[u'频道', u'文章'])
train_data.head() 

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

2 计算每个文章的词向量

# 加载训练好的Word2Vec模型
# 需要 4.0_训练word2vec模型.ipynb 的执行结果
from gensim.models import Word2Vec
w2v = Word2Vec.load('output_word2vec/model.w2v') 

# 使用文章中所有词的平均词向量作为文章的向量
import jieba
def compute_doc_vec_single(article):
    vec = np.zeros((w2v.layer1_size,), dtype=np.float32)
    n = 0
    for word in jieba.cut(article):
        if word in w2v:
            vec += w2v[word]
            n += 1
    return vec / n

def compute_doc_vec(articles):
    return np.row_stack([compute_doc_vec_single(x) for x in articles]) 
    
x = compute_doc_vec(train_data[u'文章']) 
print (x.shape)

3 训练分类器

from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split 

# 编码目标变量
y_encoder = LabelEncoder()
y = y_encoder.fit_transform(train_data[u'频道']) 

# 划分训练测试数据,根据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] 

4 .训练与评估

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

model = LogisticRegression(multi_class='multinomial', solver='lbfgs')
model.fit(train_x, train_y)
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_)
  ~  体育健康女人娱乐房地产教育文化新闻旅游汽车科技财经
体育38504321102011
健康03142200562720618
女人71332319221743370
娱乐1115308036032160
房地产1343357001341014
教育054503356323154
文化1325672723230152133
新闻8141372226252271241626
旅游151515515153126119
汽车035010075365014
科技29432312208331915
财经342229114021225279
# 计算各项评价指标
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_) #查看训练结果 

查看前五条

  ~  LabelPrecisionRecallF1Support
0体育0.9413200.96250.951792400
1健康0.8395720.78500.811370400
2女人0.7408260.80750.772727400
3娱乐0.7368420.77000.753056400
4房地产0.8459720.89250.868613400

5 模型保存

# 保存模型到文件
import dill
import pickle
model_file = os.path.join(output_dir, u'model.pkl')
with open(model_file, 'wb') as outfile:
    pickle.dump({
        'y_encoder': y_encoder,
        'lr': model
    }, outfile)

6 加载模型对新文档进行预测

from gensim.models import Word2Vec
import dill
import pickle
import jieba

# 把预测相关的逻辑封装在一个类中,使用这个类的实例来对新文档进行分类预测
class Predictor(object):
    
    def __init__(self, w2v_model_file, lr_model_file):
        self.w2v = Word2Vec.load(w2v_model_file)
        with open(lr_model_file, 'rb') as infile:
            self.model = pickle.load(infile)
    
    def predict(self, articles):
        x = self._compute_doc_vec(articles)
        y = self.model['lr'].predict(x)
        y_label = self.model['y_encoder'].inverse_transform(y)
        return y_label
    
    def _compute_doc_vec(self, articles):
        return np.row_stack([compute_doc_vec_single(x) for x in articles])

    def _compute_doc_vec_single(self, article):
        vec = np.zeros((w2v.layer1_size,), dtype=np.float32)
        n = 0
        for word in jieba.cut(article):
            if word in w2v:
                vec += w2v[word]
                n += 1
        return vec / n
# 加载新文档数据
new_data = pd.read_csv('data/sohu_test.txt', sep='\t', header=None, 
                       dtype=np.str_, encoding='utf8', names=[u'频道', u'文章'])
new_data.head() 

# 加载模型
predictor = Predictor('output_word2vec/model.w2v', model_file)

# 预测前10篇的分类
new_y_pred = predictor.predict(new_data[u'文章'][:10])

# 对比预测
pd.DataFrame({u'预测频道': new_y_pred, u'实际频道': new_data[u'频道'][:10]})

输出:
|      | 实际频道 | 预测频道 |
| ---- | --------| -------- |
| 0    | 娱乐     | 娱乐     |
| 1    | 娱乐     | 体育     |
| 2    | 娱乐     | 娱乐     |
| 3    | 娱乐     | 文化     |
| 4    | 娱乐     | 女人     |
| 5    | 娱乐     | 新闻     |
| 6    | 娱乐     | 娱乐     |
| 7    | 娱乐     | 娱乐     |
| 8    | 娱乐     | 娱乐     |
| 9    | 娱乐     | 娱乐     |
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SongpingWang

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值