AI源码解读:推荐系统案例(Python版)
上QQ阅读APP看书,第一时间看更新

项目2 PROJECT 2 小型智能健康推荐助手

本项目通过Kaggle公开数据集,进行心脏病和慢性肾病的特征筛选和提取,选择随机森林机器学习模型进行训练,预判是否有疾病、针对相应的症状或需求给出药物推荐,实现具有实用性的智能医疗助手。

2.1 总体设计

本部分包括系统整体结构和系统流程。

2.1.1 系统整体结构

系统整体结构如图2-1所示。

图2-1 系统整体结构

2.1.2 系统流程

系统流程如图2-2所示。

图2-2 系统流程

2.2 运行环境

需要Python 3.6及以上配置,在Windows环境下推荐下载Anaconda完成Python所需的配置,下载地址为https://www.anaconda.com/,也可以下载虚拟机在Linux环境下运行代码。

2.3 模块实现

本项目包括2个功能,每个功能有3个模块:疾病预测、药物推荐、模块应用,下面分别给出各模块的功能介绍及相关代码。

2.3.1 疾病预测

本模块是一个小型健康预测系统,预测两种疾病——心脏病和慢性肾病。

1.数据预处理

心脏病数据集来源地址为https://archive.ics.uci.edu/ml/datasets/Heart+Disease;慢性肾病数据集来源地址为https://www.kaggle.com/mansoordaku/ckdisease。两个数据集均包括300多名测试者的年龄、性别、静息血压、胆固醇含量等数据。

1)心脏病数据集预处理

加载数据集和数据预处理,大部分是通过Pandas库实现,相关代码如下:

# 导入相应库函数
import pandas as pd
# 读取心脏病数据集
df = pd.read_csv("../Thursday9 10 11/heart.csv")
df.head()

自动从csv中读取相应的数据,如图2-3所示。

图2-3 成功读取心脏病数据集

检查数据是否有默认值,如果有数据会显示为NaN,且当数据有默认值时不能对数据绘图可视化。

数据集没有默认值,数据的尺度比较大,通过绘图方式观察可以检查出错误数据,如图2-4所示。

图2-4 绘图观察是否有错误数据

# 通过seaborn绘图,观察数据
sns.pairplot(df.dropna(), hue= 'target ')

通过观察,第5列(血液中胆固醇含量)和第10行(静息血压)有部分点和其他点距离较大,绘制数据分布图进一步分析。

# 绘制血液中胆固醇数据分布
df['chol '].hist()
# 绘制静息血压分布图
df['treatbps '].hist()

数据分布如图2-5和图2-6所示。血液中胆固醇含量达到500,静息血压最大值达到200。经过查阅资料,静息血压正常值应该在120~140,但是接近200的患者数据,是符合实际的。取得胆固醇含量最大值的同样是患者,没有不符合实际情况的数据。

图2-5 血液中胆固醇含量

图2-6 静息血压

下面是改变数据类型,例如,胸痛类型,1~4是类别变量,它的大小并不具备比较性,但是训练时数值大小会影响权重。所以要把类别变量转化为伪变量,把4个类别拆成4件,分别用0、1表示有或没有。

转换成功后如图2-7所示。

图2-7 类别变量转换为伪变量

最后使用Scikit-learn的train_test_split()函数自动划分训练集和测试集。

2)慢性肾病数据预处理

通过Pandas读取慢性肾病数据集,读取成功效果如图2-8所示。

图2-8 成功读取慢性肾病数据集

对数据类型进行处理,例如食欲(appet)数据为good和poor,脓细胞团(pcc)为notpresent和present,将类别变量转换为伪变量0和1。

转换成功结果如图2-9所示。

图2-9 类别变量转换为伪变量

检查默认值的变量如图2-10所示。

图2-10中可以看出默认值数量不小,由于数据集不大,需要采用均值归一法,对病人和正常人分别取所有测量值的平均值来填补默认值。

图2-10 含有默认值变量

2.模型训练及保存

数据加载进模型之后,需要定义模型结构,寻找优化参数并保存模型。

1)定义模型结构

本部分包括心脏病数据集定义模型和慢性肾病数据集定义模型。

(1)心脏病数据集定义模型。

相关代码如下:

(2)慢性肾病数据集定义模型。

相关代码如下:

2)保存模型

为了能够被Python程序读取,需要将模型保存为.pkl格式的文件,利用pickle库中的模块进行模型的保存。

(1)心脏病模型保存。

相关代码如下:

(2)慢性肾病数据集定义模型。

相关代码如下:

3.模型应用

对于人的疾病来说,误诊带来的风险是极大的,正确率不是100%对患者就是损失。然而以往仅仅预测是否患上疾病,是一个二分类问题。原理上,机器对疾病的预测基于各项指标的权重。本项目充分运用机器学习的优点,将各特征重要性与各指标的数值相乘求和,得到一个加权值。在程序内部,预先对患者和正常人的各指标平均值与对应特征重要性加权求和,得到患者和正常人的平均水平。在定性判断为病人后,将用户的数值与病人均值做对比,定量给出用户的病情相对于大多数患者严重程度;如果用户被判断为正常人,则将他的各项数值与正常人均值做对比,给出用户相对于大多数正常人的亚健康程度。经过处理,不仅做到定性判断,还对用户情况进行量化。一方面防止偶然的误诊带来风险;另一方面给予患者与疾病抗争的希望,给体检正常的人敲响亚健康的警钟。

1)心脏病模型应用

输出的各特征重要性如图2-11所示。

通过图2-11可以看出,年龄因素,对患病是否有影响,并不重要,符合常识。然后分别获得患者和正常人的平均值,如图2-12所示。

图2-11 心脏病特征重要性

图2-12 心脏病患者和正常人平均值

患者和正常人加权求和后的值如图2-13所示。

图2-13 心脏病患者和正常人加权求和后的值

将这个值保存,当用户使用时,判断出是患者还是正常人之后,根据比值大小定量判断具体情况。

2)慢性肾病模型应用创新

通过eli5得到各特征重要性,输出的各特征重要性如图2-14所示。

图2-14 慢性肾病患者和正常人特征重要性

分别获得患者和正常人的平均值,如图2-15所示。

图2-15 慢性肾病患者和正常人平均值

患者和正常人加权求和后的值如图2-16所示。

图2-16 慢性肾病患者和正常人加权求和后的值

将这个值保存,当用户使用时,判断是患者还是正常人之后,根据比值大小定量出具体情况。

2.3.2 药物推荐

本模块是一个小型药物推荐系统,对800余种症状提供药物推荐。

1.数据预处理

UCI ML药品评论数据集来源https://www.kaggle.com/jessicali9530/kuc-hackathon-winter-2018 。包括超20多万条不同用户在某一种症状下服用某药物后的评论,并根据效果从1~10分进行打分。通过分析该数据集,可以对用户症状推荐大众认可的药物。

加载数据集和数据预处理,大部分通过Pandas实现,相关代码如下:

会自动从csv数据源读取相应的数据,如图2-17所示。

图2-17 成功读取心脏病数据集

数据集中有用户ID(UniqueID)、症状(condition)、服用的药物(drugName)、服用该药物后的评论(review)、打分(rating),其他用户对该用户评论的点赞数(usefulCount)。

本项目根据用户对药物的打分判断是否推荐在该症状下服用此药物。打分为1分和10分可以认为用户不推荐和推荐该药物。然而,用户对药物的打分不只是1分和10分,一般来说,对一种药物有时有效但见效慢、好用但昂贵、有所缓解但效果不明显、副作用不容忽视等。打4分不一定代表评价者的否定态度,打6分也不一定意味着评价者支持。样本总量如图2-18所示,打1分和10分的评论总量如图2-19所示,用户打分分布如图2-20所示。

图2-18 样本总量

图2-19 1分和10分的评论总量

图2-20 用户打分

打分分布如图2-20所示。

图2-19和图2-20可以看出,超过一半的用户打1分和10分,样本数据量足够机器学习用户情感,使用学习到的情感,分析打分在2~9分的用户就是内心深处支持与否。打分为1分和10分的评论情感分析学习如图2-21所示。

图2-21 仅取出打分为1分和10分的评论情感分析学习

评论(review)中,句子两端有引号,编写函数将引号删除。

发现一句话中经常出现不合时宜的符号,该数据集是网络爬虫爬取的,所以有很多字符表示成ASCII码,防止被误识别为分隔,使用正则表达式从审阅文本中删除这些符号。

评论(review)中,句子两端有引号,编写函数将引号删除。

预测的标签是喜欢与不喜欢,但是drugName和condition种类很多,写进程序中可以简化工作量,所以需要将drugName和condition列前置到review中,并将完整的字符串保存为text列。

CountVectorizer类将文本中的词语转换为词频矩阵。通过分词后把所有文档中的全部词作为一个字典,将每行的词用0、1矩阵表示。并且每行的长度相同,长度为字典的长度,在词典中存在,置为1,否则为0。由于大部分文本只用词汇表中很少一部分词,因此,词向量中有大量的0,说明词向量是稀疏的,在实际应用中使用稀疏矩阵存储。

2.模型训练及应用

相关代码如下:

仅取出打分为1分和10分的评论进行情感分析学习,如图2-22所示,打分2~9分的评论如图2-23所示,代入模型分析评论情感为支持或不支持如图2-24所示。

图2-22 仅取出打分为1分和10分的评论进行情感分析学习

图2-23 打分为2~9分的评论

图2-24 代入模型分析评论情感为支持或不支持

由于是评1分和10分,所以正确率高,接下来将训练好的模型应用到打分为2~9分的评论中。

#读取2~9分的评论
Train_0 = train_0[train.rating.isin([2,3,4,5,6,7,8,9])]
Train_0.head()

将评论经过数据预处理后,代入训练好的模型,得到评论感情分类。

3.模型应用

将两个csv文件合并成一个,本项目对某一特定症状选取支持率前三名的药物。

得到一个csv数据库,但是数据库中除了特定的药物名称,还有一些特殊字符,通过编写Python脚本文件将它们清理干净。

2.3.3 模型测试

本部分包括模型导入及相关代码。

1.模型导入

输入数据包括两部分:如性别、年龄、食欲需要用户手动输入;心率、心电图波形参数,需要用户接入不同的传感器测量。考虑到应用的便捷性,直接从传感器读取所有的参数进行预测。

一位用户输入的数据如图2-25所示,判决结果如图2-26所示。

图2-25 一位用户的数据

图2-26 判决结果

client_result=rf.predict(client_x)
print('这就是分类预测结果')
print(client_result)

根据数据和模型,首先判断病与非病;其次判断病情严重程度,不能只用是否有病,而是给病情不同程度的评价。将数据乘以每个因素的权重和有病的人平均值做对比。如果直接告诉一个人,得病了,可能无法接受。如果说明情况不太严重,比大多数病人轻,量化后,容易接受,如图2-27所示。

图2-27 量化

之前平均值是病人比正常人的小,所以大于分界面更好。病情指数比平均数的四分之一还小,量化后督促病人抓紧时间治疗。

2.相关代码

本部分包括模型预测代码、模型应用创新代码、用户接口及界面可视化代码。

1)模型预测

相关代码如下:

2)模型应用创新

相关代码如下:

3)用户接口及界面可视化

本部分为主界面GUI设计及子界面调用。

2.4 系统测试

本部分包括训练准确度、测试效果和模型应用。

2.4.1 训练准确度

心脏病预测准确率达到89%以上,模型训练比较成功,如图2-28~图2-31所示。

图2-28 模型准确率

图2-29 混淆矩阵

图2-30 ROC曲线

图2-31 ROC曲线面积

慢性肾病预测准确率达到100%,如图2-32~图2-35所示。

图2-32 模型准确率

图2-33 混淆矩阵

图2-34 ROC曲线

图2-35 ROC曲线面积

2.4.2 测试效果

将数据代入模型进行测试,分类的标签与原始数据进行显示和对比,可以得到验证:模型可以实现疾病预测和药物推荐。模型训练效果如图2-36所示,药物推荐效果如图2-37所示。

图2-36 模型训练效果

图2-37 药物推荐效果

2.4.3 模型应用

打开cmd命令,到程序所在文件夹;输入python test.py开始测试;打开应用,初始界面如图2-38所示。

图2-38 应用初始界面

界面从上至下,分别有三个按钮。单击第一个按钮“健康预测”,可以看到界面跳转到疾病预测界面,如图2-39所示。

图2-39 疾病预测显示界面

返回主界面后,单击第二个按钮“药物推荐”,看到界面跳转到药物推荐界面,如图2-40所示;药物推荐助手如图2-41所示;对不在数据库中的症状,提示不存在,不输出任何疾病信息,如图2-42所示。

图2-40 药物推荐显示界面

图2-41 测试结果

图2-42 药物推荐助手