介绍
麻烦的人工智导的作业(不是我的),依据下面数据库和规则库,用 Python 设计一个基于产生式系统的病情诊断系统。要求用户输入相关症状情况,系统根据诊断规则判断出对应的疾病。请根据诊断规则编写程序:
感冒:{症状1:{鼻塞,流涕,头痛},症状2:{发热,喉咙痛},症状3:{乏力,肌肉疼痛}} |
下面是诊断规则:
感冒:如果感冒的症状1、症状2和症状3都出现,那么可能是感冒。 |
算法的描述
初始化和数据结构:
我们使用面向对象编程,首先定义了一个 DiseaseDiagnosisSystem 类,包括了一些初始化工作。对于疾病诊断系统,使用类的封装性,可以控制对数据和方法的访问,确保数据的完整性并隐藏实现细节。这样可以更好地管理系统的状态和行为。对于这个题目,我们分为四个部分编程。分别是在类中内置数据库、记录症状、进行诊断、输出结果。主要框架如下:
class DiseaseDiagnosisSystem: |
用户交互:
首先我们需要引导用户输入正确的症状,所以我们在类中创建了一个症状列表,该列表中列出了所有可以诊断的症状。
self.symptoms = ["鼻塞", "流涕", "头痛", "发热", "高热", "喉咙痛", "咳嗽", "乏力", "肌肉疼痛", "胃疼", "恶心", "呕吐", "食欲不振", "嗳气", "体重下降", "肝区疼痛", "黄疸", "易疲劳", "尿液异常", "水肿", "高血压"] |
同时在类中定义一个list_symptoms
函数,作用是在用户输入前打印出用户能够选择的症状。
def list_symptoms(self): |
.join
是python自带的函数,含义是将列表中的每个成员以字符’,'分隔开再拼接成一个字符串
使用 while
循环来获取用户的输入,当用户输入一个症状回车时,比如用户输入"发热",判断用户输入的值是否为exit
,若是则跳出循环,若不是则将"发热"赋值给symptom,然后将symptom传递给类中的add_symptom
函数,执行症状记录。
system.list_symptoms() # 调用类中的函数,引导用户输入 |
症状记录
那么如何编写add_symptom函数使其能够执行症状记录的功能呢?
首先创建一个疾病嵌套字典,名为diseases
,字典的键为”感冒“”流感“…值为”症状1“”症状2“的嵌套字典,症状1症状2的值为具体症状,创建的字典如下:
diseases = { |
但是仅仅创建一个疾病字典并不能实现对症状的计数,所以同时我们又创建了一个计数字典,计数字典的键为症状,值为[症状1,症状2,症状3]的计数列表,如下
self.symptom_counts = { |
我们的想法是当用户输入一个症状时,我们遍历疾病字典,看用户输入的疾病是否在疾病字典中存在。若存在,则在计数字典中症状出现的相应位置+1。比如当用户输入鼻塞时,遍历diseases字典,找到鼻塞在感冒和流感的症状1的位置,然后再计数字典中更新感冒和流感的计数列表以此实现用户疾病的计数。
需要着重注明的是数据的类型,这里数据类型把我看裂开。
# items() 遍历方法把字典中每对 key 和 value 组成一个元组,并把这些元组放在列表中返回。 |
诊断算法:
当然仅仅是计数还不能满足我们的要求,我们还需要根据规则库来判断用户可能患有的疾病。所以首先先建立一个空列表 possible_diseases
代表用户可能患有的疾病,当用户输入症状的时候,在更新计数字典的同时我们把对应的疾病名称添加到该列表中
def diagnose(self): |
当然这只是用户可能患有的疾病,我们还需要根据规则库来进一步判断。但是在实现算法的过程中,我们发现在用户多次输入同一个症状的内容时程序会不停的计数,对后续的诊断会产生影响,所以我们在诊断之前先将计数列表中大于0的值置1,然后根据计数字典中"感冒"列表值的和是否为3来决定输出。
# 将计数列表self.symptom_counts中大于0的值置1,避免当用户输入症状过少或者用户一直输入症状1的内容时程序误判 |
和用户可能患有的疾病一样,创建一个results结果空列表。我们遍历possible_diseases中记录的疾病,根据规则库来判断用户的症状是否满足规则库,比如当用户输入"鼻塞"“发热”"乏力"的时候,计数字典中"感冒"列表就会变成[1,1,1],此时使用sum求和计算列表值的和。
results = [] |
根据规则库,在诊断过程中,针对特定的疾病(如流感、胃炎、肾炎),还需要进一步对一些特定的问题询问,以更准确地诊断出疾病。
def ask_duration_question(self, disease): |
实验结果及分析
运行结果
模拟用户输入多种症状以及输入无关项时的程序输出结果
可供选择的症状有:鼻塞, 流涕, 头痛, 发热, 高热, 喉咙痛, 咳嗽, 乏力, 肌肉疼痛, 胃疼, 恶心, 呕吐, 食欲不振, 嗳气, 体重下降, 肝区疼痛, 黄疸, 易疲劳, 尿液异常, 水肿, 高血压 |
优化
程序本身经过了多次优化,在最初的版本中由于没有考虑到用户的需求,在用户输入多种符合症状的疾病时只能输出一种结果。并且对于这种严谨程度高的医疗诊断系统来说,还需要测试模块来保证程序的运行结果。程序还有许多可以优化的地方,我们自认为另外创建一个字典用于计数或多或少是做的复杂了,或许根据嵌套字典中症状键值的布尔值来改变症状的键为布尔值是一种可行的方法,又或者可以减少字典和嵌套循环的使用来减少程序的运行时间和占用。而且也不一定需要使用列表来记录症状合集,增加重复的工作并且不好维护,这都是可以优化的地方。
完整代码
# 定义了一个名为 DiseaseDiagnosisSystem 的类 |
吐槽
这玩意儿和人工智能有关系吗?就是逻辑 if...else
判断。。。还有和一个python忘光光的人(列表都忘了)解释代码逻辑真的好难,我还专门写了这个文档为了他们做 pre 用,哭死😭。