人工智能
第十章 中文分词
一、安装 jieba 中文分词组件
1. 全自动安装
- pip install jieba / pip3 install jieba
2. 半自动安装
- 先下载 http://pypi.python.org/pypi/jieba/, 解压后运行 python setup.py install
3. 手动安装
- 将 jieba 目录放置于当前目录或者 site-packages 目录
二、文本分词
1. jieba 提供了两种常用的分词方法
- jieba.cut() 普通分词:通过cut_all=True参数来控制是否采用全模式
- jieba.cut_for_search() 搜索引擎分词:该方法适合用于搜索引擎构建倒排索引的分词,粒度比较细
import jieba
seg_list
2. 添加自定义词典
- 开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词。虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率。
- 用法:jieba.load_userdict(file_name) # file_name 为文件类对象或自定义词典的路径
- 词典格式和 dict.txt 一样,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。file_name 若为路径或二进制方式打开的文件,则文件必须为 UTF-8 编码。
- 词频忽略时使用自动计算的能保证分出该词的词频。
创新办 3 i
云计算 5
凯特琳 nz
台中
!pip install jieba
import numpy as np
import jieba
# 全模式
seg_list = jieba.cut("我来到北京清华大学", cut_all=True)
' / '.join(seg_list)
"""
'我 / 来到 / 北京 / 清华 / 清华大学 / 华大 / 大学'
"""
# 精确模式
# seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
seg_list = jieba.cut("我来到北京清华大学")
' / '.join(seg_list)
"""
'我 / 来到 / 北京 / 清华大学'
"""
# 搜索引擎模式
seg_list = jieba.cut("小明毕业于中国科学院研究所,后在日本京都大学深造")
' / '.join(seg_list)
"""
'小明 / 毕业 / 于 / 中国科学院 / 研究所 / , / 后 / 在 / 日本京都大学 / 深造'
"""
jieba.load_userdict('mydict.txt')
seg_list = jieba.cut("乒乓球拍卖完了")
' / '.join(seg_list)
seg_list = jieba.cut("张平平安全到家了")
' / '.join(seg_list)
"""
'张平 / 平安 / 全到 / 家 / 了'
"""
mydict.txt
乒乓球拍 100
张平 1000
平安 300
安全 299
大床房
3. 酒店评论分析
- 基于酒店评论数据集 htl.csv 训练模型,完成情感分析。
import numpy as np
import pandas as pd
import sklearn.model_selection as ms
import sklearn.naive_bayes as nb
import sklearn.metrics as sm
import jieba
jieba.load_userdict('mydict.txt')
# 加载文件
data = pd.read_csv('htl_all.csv')
data['label'].value_counts()
"""
1 5322
0 2443
Name: label, dtype: int64
"""
data['review'] # 评论内容
"""
0 距离川沙公路较近,但是公交指示不对,如果是"蔡陆线"的话,会非常麻烦.建议用别的路线.房间较...
1 商务大床房,房间很大,床有2M宽,整体感觉经济实惠不错!
2 早餐太差,无论去多少人,那边也不加食品的。酒店应该重视一下这个问题了。房间本身很好。
3 宾馆在小街道上,不大好找,但还好北京热心同胞很多~宾馆设施跟介绍的差不多,房间很小,确实挺小...
4 CBD中心,周围没什么店铺,说5星有点勉强.不知道为什么卫生间没有电吹风
...
7760 尼斯酒店的几大特点:噪音大、环境差、配置低、服务效率低。如:1、隔壁歌厅的声音闹至午夜3点许...
7761 盐城来了很多次,第一次住盐阜宾馆,我的确很失望整个墙壁黑咕隆咚的,好像被烟熏过一样家具非常的...
7762 看照片觉得还挺不错的,又是4星级的,但入住以后除了后悔没有别的,房间挺大但空空的,早餐是有但...
7763 我们去盐城的时候那里的最低气温只有4度,晚上冷得要死,居然还不开空调,投诉到酒店客房部,得到...
7764 说实在的我很失望,之前看了其他人的点评后觉得还可以才去的,结果让我们大跌眼镜。我想这家酒店以...
Name: review, Length: 7765, dtype: object
"""
def func(item):
# 分词
seg_list = jieba.cut(item)
return ' '.join(seg_list)
data['new_review'] = data['review'].apply(func)
data
import sklearn.feature_extraction.text as ft
# 整理输入集与输出集 TFIDF 把每一封邮件转成一个特征向量
cv = ft.CountVectorizer()
bow = cv.fit_transform(data['new_review'])
tt = ft.TfidfTransformer()
tfidf = tt.fit_transform(bow)
# tfidf.shape # (2968,40605)
# 拆分测试集与训练集
train_x, test_x, train_y, test_y = ms.train_test_split(tfidf, data['label'], test_size=0.1, random_state=7)
# 交叉验证
# 使用朴素贝叶斯
import sklearn.naive_bayes as nb
model = nb.MultinomialNB()
scores = ms.cross_val_score(model, tfidf, data['label'], cv=5, scoring='f1_weighted')
# f1得分
print(scores.mean()) # 0.9597980963781605
# 训练模型
model.fit(train_x, train_y)
# 测试模型,评估模型
pred_test_y = model.predict(test_x)
print(sm.classification_report(test_y, pred_test_y))
"""
0.682265830766706
precision recall f1-score support
0 0.92 0.20 0.33 220
1 0.76 0.99 0.86 557
accuracy 0.77 777
macro avg 0.84 0.60 0.60 777
weighted avg 0.80 0.77 0.71 777
"""
test_data = ["这家酒店棒,环境棒,电视棒,空调不错,挺好的。",
"地板脏,空调漏水,再也不来了!",
"空调不太凉,早餐还行,但是服务差了点,总体一般。"]
test_data = pd.Series(test_data).apply(func)
# 把样本按照训练时的方式转换成tfidf矩阵,才可以交给模型进行预测
bow = cv.transform(test_data)
test_data = tt.transform(bow)
pred_test_y = model.predict(test_data)
print(pred_test_y)
"""
[1 0 1]
"""
第十一章 样本均衡化与置信概率
一、样本类别均衡化
- 模型训练过程中由于样本类别数量不均衡,将导致模型会偏向样本数量较多的类别,保证该类别的召回率。但这样会影响其他类别的预测效果。可以采用上采样与下采样的方式进行样本处理:
- 下采样:把样本数据量大的那一类样本减少到与数据量小的那一类样本数量相近。
- 上采样:把样本数据量小的那一类样本增加到与数据量大的那一类样本数量相近。
import numpy as np
import pandas as pd
import sklearn.model_selection as ms
import sklearn.naive_bayes as nb
import sklearn.metrics as sm
import jieba
jieba.load_userdict('mydict.txt')
# 加载文件
data = pd.read_csv('htl_all.csv')
# 只要后半部分的样本数量(两倍的差评样本数量)
data = data.tail((data['label'] == 0).sum() * 2)
data['label'].value_counts()
"""
1 2443
0 2443
Name: label, dtype: int64
"""
def func(item):
# 分词
seg_list = jieba.cut(item)
return ' '.join(seg_list)
data['new_review'] = data['review'].apply(func)
import sklearn.feature_extraction.text as ft
# 整理输入集与输出集 TFIDF 把每一封邮件转成一个特征向量
cv = ft.CountVectorizer()
bow = cv.fit_transform(data['new_review'])
tt = ft.TfidfTransformer()
tfidf = tt.fit_transform(bow)
# tfidf.shape # (2968,40605)
# 拆分测试集与训练集
train_x, test_x, train_y, test_y = ms.train_test_split(tfidf, data['label'], test_size=0.1, random_state=7)
# 交叉验证
# 使用朴素贝叶斯
import sklearn.naive_bayes as nb
model = nb.MultinomialNB()
scores = ms.cross_val_score(model, tfidf, data['label'], cv=5, scoring='f1_weighted')
# f1得分
print(scores.mean()) # 0.9597980963781605
# 训练模型
model.fit(train_x, train_y)
# 测试模型,评估模型
pred_test_y = model.predict(test_x)
print(sm.classification_report(test_y, pred_test_y))
"""
0.8595398913507326
precision recall f1-score support
0 0.88 0.88 0.88 252
1 0.87 0.87 0.87 237
accuracy 0.88 489
macro avg 0.88 0.88 0.88 489
weighted avg 0.88 0.88 0.88 489
"""
test_data = ["这家酒店棒,环境棒,电视棒,空调不错,挺好的。",
"地板脏,空调漏水,再也不来了!",
"空调不太凉,早餐还行,但是服务差了点,总体一般。",
"我不喜欢。"]
test_data = pd.Series(test_data).apply(func)
# 把样本按照训练时的方式转换成tfidf矩阵,才可以交给模型进行预测
bow = cv.transform(test_data)
test_data = tt.transform(bow)
pred_test_y = model.predict(test_data)
print(pred_test_y)
"""
[1 0 1 0]
"""
- 除了上述解决方案以外,sklearn 还为多数模型提供了 class_weight 参数来实现样本类别均衡化设置:
model = svm.SVC(
kernel='linear', class_weight='balanced')
model.fit(train_x, train_y)
# 还可以如下设置:
class_weight={0:0.9, 1:0.1}
二、置信概率
预测酒店评论是好评还是差评:
1. 房间真棒,离大马路很近,非常方便。不错。 好评 0.9954
2. 房间有点脏,厕所还漏水,空调不制冷,下次再也不来了。 差评 0.99
3. 地板不太干净,电视没信号,但是空调还可以,总之还行。 好评 0.56
- 不同的模型,置信概率的算法也不同,该值可以作为估测可信程度的指标。
三、置信概率实现
- sklearn 为多数分类模型提供了 predict_proba() 方法来获取置信概率:
# 在获取模型时,给出超参数probability=True
model = svm.SVC(kernel='rbf', C=600, gamma=0.01, probability=True)
# 调用model.predict_proba(样本矩阵)可以获取每个样本的置信概率矩阵
置信概率矩阵 = model.predict_proba(输入样本矩阵)
test_data = ["这家酒店棒,环境棒,电视棒,空调不错,挺好的。",
"地板脏,空调漏水,再也不来了!",
"空调不太凉,早餐还行,但是服务差了点,总体一般。",
"我不喜欢。", "哪哪都好!房间大,视野开阔,环境非常好,下次还来!"]
test_data = pd.Series(test_data).apply(func)
# 把样本按照训练时的方式转换成tfidf矩阵,才可以交给模型进行预测
bow = cv.transform(test_data)
test_data = tt.transform(bow)
pred_test_y = model.predict(test_data)
# 输出置信概率
pred_prob_y = model.predict_proba(test_data)
print(pred_test_y)
probs = pred_prob_y.max(axis=1)
for b,c in zip(pred_test_y, probs):
print(b, ':', c)
"""
[1 0 1 0 1]
1 : 0.5594777973826913
0 : 0.8753288789559337
1 : 0.6186367347028627
0 : 0.542983041059403
1 : 0.8376674099240857
"""