Mycin: a medical expert system.
This is a small example of an expert system that uses the Emycin shell. It defines a few contexts, parameters, and rules, and presents a rudimentary user interface to collect data about an infection in order to determine the identity of the infecting organism.
In a more polished system, we could:
This implementation comes from chapter 16 of Peter Norvig's "Paradigms of Artificial Intelligence Programming.
Function for testing value equality.
def eq(x, y):
return x == y
Function for reading True or False from a string. Raises an error if the string is not True or False.
def boolean(string):
if string == 'True':
return True
if string == 'False':
return False
raise ValueError('bool must be True or False')
Here we define the contexts, parameters, and rules for our system. This is the job of the expert, and in a more polished system, we would define and use a domain-specific language to make this easier.
def define_contexts(sh):
Patient and Culture have some initial goals--parameters that should be collected before reasoning begins. This might be useful in some domains; for example, this might be legally required in a medical system.
sh.define_context(Context('patient', ['name', 'sex', 'age']))
sh.define_context(Context('culture', ['site', 'days-old']))
Finding the identity of the organism is our goal.
sh.define_context(Context('organism', goals=['identity']))
def define_params(sh):
Patient params
sh.define_param(Parameter('name', 'patient', cls=str, ask_first=True))
sh.define_param(Parameter('sex', 'patient', enum=['M', 'F'], ask_first=True))
sh.define_param(Parameter('age', 'patient', cls=int, ask_first=True))
sh.define_param(Parameter('burn', 'patient',
enum=['no', 'mild', 'serious'], ask_first=True))
sh.define_param(Parameter('compromised-host', 'patient', cls=boolean))
Culture params
sh.define_param(Parameter('site', 'culture', enum=['blood'], ask_first=True))
sh.define_param(Parameter('days-old', 'culture', cls=int, ask_first=True))
Organism params
organisms = ['pseudomonas', 'klebsiella', 'enterobacteriaceae',
'staphylococcus', 'bacteroides', 'streptococcus']
sh.define_param(Parameter('identity', 'organism', enum=organisms, ask_first=True))
sh.define_param(Parameter('gram', 'organism',
enum=['acid-fast', 'pos', 'neg'], ask_first=True))
sh.define_param(Parameter('morphology', 'organism', enum=['rod', 'coccus']))
sh.define_param(Parameter('aerobicity', 'organism', enum=['aerobic', 'anaerobic']))
sh.define_param(Parameter('growth-conformation', 'organism',
enum=['chains', 'pairs', 'clumps']))
def define_rules(sh):
sh.define_rule(Rule(52,
[('site', 'culture', eq, 'blood'),
('gram', 'organism', eq, 'neg'),
('morphology', 'organism', eq, 'rod'),
('burn', 'patient', eq, 'serious')],
[('identity', 'organism', eq, 'pseudomonas')],
0.4))
sh.define_rule(Rule(71,
[('gram', 'organism', eq, 'pos'),
('morphology', 'organism', eq, 'coccus'),
('growth-conformation', 'organism', eq, 'clumps')],
[('identity', 'organism', eq, 'staphylococcus')],
0.7))
sh.define_rule(Rule(73,
[('site', 'culture', eq, 'blood'),
('gram', 'organism', eq, 'neg'),
('morphology', 'organism', eq, 'rod'),
('aerobicity', 'organism', eq, 'anaerobic')],
[('identity', 'organism', eq, 'bacteroides')],
0.9))
sh.define_rule(Rule(75,
[('gram', 'organism', eq, 'neg'),
('morphology', 'organism', eq, 'rod'),
('compromised-host', 'patient', eq, True)],
[('identity', 'organism', eq, 'pseudomonas')],
0.6))
sh.define_rule(Rule(107,
[('gram', 'organism', eq, 'neg'),
('morphology', 'organism', eq, 'rod'),
('aerobicity', 'organism', eq, 'aerobic')],
[('identity', 'organism', eq, 'enterobacteriaceae')],
0.8))
sh.define_rule(Rule(165,
[('gram', 'organism', eq, 'pos'),
('morphology', 'organism', eq, 'coccus'),
('growth-conformation', 'organism', eq, 'chains')],
[('identity', 'organism', eq, 'streptococcus')],
0.7))
import logging
from paip.emycin import Parameter, Context, Rule, Shell
def report_findings(findings):
for inst, result in findings.items():
print 'Findings for %s-%d:' % (inst[0], inst[1])
for param, vals in result.items():
possibilities = ['%s: %f' % (val[0], val[1]) for val in vals.items()]
print '%s: %s' % (param, ', '.join(possibilities))
def main():
sh = Shell()
define_contexts(sh)
define_params(sh)
define_rules(sh)
report_findings(sh.execute(['patient', 'culture', 'organism']))