Prolog 医学诊断在诊断疾病时犯了什么错误?
我正在制作诊断病人的专家系统。我很难问所有关于症状的问题,然后给出疾病的结果。谢谢你的帮助 这是规则 疟疾症状=发烧、颤抖、出汗、头痛 斑疹伤寒的症状=发烧、恶心、肠胃胀气、腹痛、心脏灼伤、臭屁或大便 阑尾炎的症状=发烧、恶心、腹痛、下腹部疼痛、右腹部疼痛 我必须向用户询问这10个关于症状的问题,并阅读答案。 例如: 发烧?:对 颤抖对 出汗?:没有 头痛?:没有 恶心?:对 气胀?:对 腹痛或腹痛对 心脏灼伤没有 闻到屁或大便的味道没有 下腹部、右腹部疼痛没有 节目提问后,节目应该给出这样的疾病结果 诊断:疟疾、斑疹伤寒、阑尾炎 诊断为疟疾、斑疹伤寒、阑尾炎=>因为疟疾有2种症状,斑疹伤寒有4种症状,阑尾炎有3种症状 我代码的问题是程序在显示所有问题之前给出诊断结果 这就是编码Prolog 医学诊断在诊断疾病时犯了什么错误?,prolog,diagnostics,expert-system,Prolog,Diagnostics,Expert System,我正在制作诊断病人的专家系统。我很难问所有关于症状的问题,然后给出疾病的结果。谢谢你的帮助 这是规则 疟疾症状=发烧、颤抖、出汗、头痛 斑疹伤寒的症状=发烧、恶心、肠胃胀气、腹痛、心脏灼伤、臭屁或大便 阑尾炎的症状=发烧、恶心、腹痛、下腹部疼痛、右腹部疼痛 我必须向用户询问这10个关于症状的问题,并阅读答案。 例如: 发烧?:对 颤抖对 出汗?:没有 头痛?:没有 恶心?:对 气胀?:对 腹痛或腹痛对 心脏灼伤没有 闻到屁或大便的味道没有 下腹部、右腹部疼痛没有 节目提问后,节目应该给出这样的疾
go :- diagnosis(X),
write('diagnosis are : '),nl,
write(X),nl,fail.
diagnosis(_) :- retractall, fail.
diagnosis(malaria) :- fever(yes), shivering(yes), sweating(yes), headache(yes).
diagnosis(tipes) :- fever(yes), nausea(yes), flatulence(yes), abdominal_pain_intemittent(yes), heart_burn(yes), smelling_fart_or_stool(yes).
diagnosis('usus buntu') :- fever(yes), nausea(yes),abdominal_pain_intemittent(yes), ain_in_lower_right_abdominal(yes).
fever(X) :- ask(fever,X).
shivering(X) :- ask(shivering,X).
sweating(X) :- ask(sweating,X).
headache(X) :- ask(headache,X).
nausea(X) :- ask(nausea,X).
flatulence(X) :- ask(flatulence,X).
abdominal_pain_intemittent(X) :- ask('abdominal_pain_intemittent',X).
heart_burn(X) :- ask('heart_burn',X).
smelling_fart_or_stool(X) :- ask('smelling_fart_or stool',X).
pain_in_lower_right_abdominal(X) :- ask('pain_in_lower_right_abdominal',X).
known(yes, a, b).
ask(A, V):- known(yes, A, V), !.
ask(A, V):- known(_, A, V), !, fail.
ask(A, _):- known(yes, A, _), !, fail.
ask(A, V):- write(A:V), write('? : '), read(Y), asserta(known(Y, A, V)), Y == yes.
retractall :- retract(known(_,_,_)).
通过使用
trace/0
,您可以很容易地了解为什么在所有十个问题被询问之前,您会得到诊断。我建议您尝试一下,因为它对调试Prolog程序非常有帮助
理解的关键是思考反向链接是如何工作的,即Prolog如何回答查询。Prolog希望回答“true”,但要做到这一点,它必须找到满足查询的变量绑定。当你问它“开始”时,你问它的第一件事是诊断(X)。因此,为了证明“go”是真的,它必须找到满足诊断(X)的X
。为了证明这一点,它必须输入diagnosis/1。
从那里开始,您就有了一个乏味的retractall,fail
目标,它将首先输入,并且(最终)总是失败。然后进入诊断(疟疾),这取决于发烧、颤抖、出汗和头痛四种症状。这就是为什么Prolog会提示您这四个症状。假设你对所有四个人说“是”,诊断(疟疾)成功!然后返回go,X=malia
,它将继续打印诊断结果
对我来说,这个程序是一个非常古老的编写序言的方法的好例子。您的I/O中混合了许多声明性内容,您使用事实数据库作为读/写存储,并且您使用失败以过程方式驱动某些副作用。我倾向于把责任推到教授或教科书的脚上,但无论如何,要改进这个程序或用这种风格理解Prolog都是非常困难的
要解决此问题,最简单的方法是使用单独的流程,在执行diagnosis/1
之前收集症状。更改如下所示:
go :-
retractall,
ask_everything,
diagnosis(X),
write('diagnosis are : '),nl,
write(X),nl,fail.
ask_everything :-
fever(yes), shivering(yes), sweating(yes), headache(yes),
nausea(yes), flatulence(yes), abdominal_pain_intemittent(yes),
heart_burn(yes), smelling_fart_or_stool(yes),
pain_in_lower_right_abdominal(yes).
?- go.
fever:yes? : yes.
shivering:yes? : |: yes.
sweating:yes? : |: yes.
headache:yes? : |: yes.
nausea:yes? : |: no.
diagnoses are:
malaria
true.
?-
同时删除诊断(u)的第一个子句:-retractall,fail
,否则您的情况不会比以前好
这仍然相当糟糕,但它可能会让你渡过难关
从长远来看,一般来说,您可能希望专家系统以交互方式执行面试。毕竟,询问某人是否感到胃灼热是没有意义的,除非他们感到肠胃胀气并且符合斑疹伤寒诊断标准;胃灼热的症状与其他两种诊断(疟疾或通常的本图)无关,找出这种依赖关系只有Prolog能做到。这并不意味着Prolog必须在诊断阶段输出任何东西;通过将访谈/数据收集阶段与结果输出阶段分开,只需收集所有诊断,然后将其输出,就可以两全其美。结果如下:
go :-
retractall,
findall(X, diagnosis(X), Diagnoses),
writeln('diagnoses are: '),
display_diagnoses(Diagnoses).
display_diagnoses([]).
display_diagnoses([X|Rest]) :-
write(' '), write(X), nl,
display_diagnoses(Rest).
运行它看起来像这样:
go :-
retractall,
ask_everything,
diagnosis(X),
write('diagnosis are : '),nl,
write(X),nl,fail.
ask_everything :-
fever(yes), shivering(yes), sweating(yes), headache(yes),
nausea(yes), flatulence(yes), abdominal_pain_intemittent(yes),
heart_burn(yes), smelling_fart_or_stool(yes),
pain_in_lower_right_abdominal(yes).
?- go.
fever:yes? : yes.
shivering:yes? : |: yes.
sweating:yes? : |: yes.
headache:yes? : |: yes.
nausea:yes? : |: no.
diagnoses are:
malaria
true.
?-
这在我看来是一个显著的改进,没有实质性的代码更改。希望这有帮助
哦,还有一件事:将retractall:-retract(已知(,,,,))替换为retractall:-retractall(已知(,,,,))
)
我还建议您更仔细地格式化代码!不重新格式化就很难理解。规范卫生事项 谢谢你的帮助。