词袋 不关注词的先后顺序---词袋模型(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()
# 载入停用词
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())
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()
# 加载模型
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)