JavaScript 实现动物识别专家系统交互演示

本文首发且更新于个人博客: https://www.xerrors.fun/Animal-Identification-Expert-System/

前言:本篇文章主要是介绍什么是专家系统,接下来会使用 JavaScript 语言来实现专家系统,同时完成在线交互演示的功能,使用的是 Vue 框架,没有把全部代码给贴出来,仅仅贴出来与算法相关的部分,如果想看全部的代码或者编辑这些代码,可以到 「Codepen」 体验。如果仅仅想要体验交互程序可以到我的「个人博客」 。而且我不想在非专业的文章里面出现很多的专有词汇,所以整篇文章会偏向于口语化,适合课后用来理解。

1. 专家系统介绍

在专家系统中,用户可以通过输入动物的特征,从系统中获得是什么动物。在系统内部,有若干个规则,系统基于已经存在的规则,对用户的输入进行判断,给出最终结果。这个系统就相当于一个动物领域的专家,你只要告诉他动物的特征,他就可以根据过往的经验来判断出你说的是什么动物。

想要达到这个地步,需要两样东西:一个是你要有足够的经验才能成为专家,其次就是你要能够运用这些知识,不然还不如一本书呢。

维基百科对 专家系统 的解释。专家系统= 知识库 + 推理机 ,因此专家系统也被称为基于知识的系统。专家系统其实也有好几个分类,这里所介绍的动物识别专家系统实际上就是一个基于规则的前向链专家系统(Forward-Chain Rule-Based Expert System),也就是我们是已知动物的特征去推算动物的种类。下面是两个规则的例子(字丑勿怪):

规则1:如果有毛且有蹄,可推出食草动物

规则2:如果长脖子且是食草动物,可推出长颈鹿

2. 知识库

下面的例子会借助一个具有对七个动物的识别的例子来详细介绍什么是专家系统:「企鹅、海燕、鸵鸟、斑马、长颈鹿、虎、金钱豹」。然后我们使用 31 个词来描述动物的特征,也就是下面的 Features 。其中前 20 个是最基础的,是用户的可输入的特征,而「哺乳类、鸟类、肉食类、蹄类」 这四个是中间推导结果;最后七个特征是七种动物。对于这些特征我们使用一个数组来保存。

为了方便大家理解这些特征跟序号的对应关系,大家看图:

扫描二维码关注公众号,回复: 11290591 查看本文章

保存规则

在线演示需要使用 JavaScript 作为编程语言,这里我们首先使用一个字符串数组来保存这些特征,使用一个对象数组来保存这些规则,然后使用一个布尔数组来保存推理的结果。比如若推导出是鸟类,则将 result[21] 置为 true

features: ["有毛","产奶","有羽毛","会飞","会下蛋","吃肉","有犬齿","有爪","眼睛盯前方","有蹄","反刍","黄褐色","有斑点","有黑色条纹","长脖","长腿","不会飞","会游泳","黑白两色","善飞","哺乳类","鸟类","肉食类","蹄类","企鹅","海燕","鸵鸟","斑马","长颈鹿","虎","金钱豹"],
rules: [
    {
        conditions: [0],  // 条件
        conclusion: 20    // 结论
    }, {
        conditions: [1],  // 若产奶,则是哺乳类
        conclusion: 20
    }, 
    …… // 中间的规则省略了
    {
    	conditions: [22, 11, 12], 
    	conclusion: 30 // 若是肉食类且黄褐色且有斑点, 则是金钱豹
}],
result: Array(31).fill(false), // 表示推理的结果

对于 C,C++ 等编程语言,可以使用结构体的形式来保存规则。

char *feature[]={"有毛","产奶","有羽毛","会飞","会下蛋","吃肉","有犬齿","有爪","眼睛盯前方","有蹄","反刍","黄褐色","有斑点","有黑色条纹","长脖","长腿","不会飞","会游泳","黑白两色","善飞","哺乳类","鸟类","肉食类","蹄类","企鹅","海燕","鸵鸟","斑马","长颈鹿","虎","金钱豹"};

// 创建一个结构体
typedef struct  
{
	int conditions[5]; // 条件
    int conclusion;    // 结论
}Rule;

// 规则
Rule rule[15]={
	{{0,-1},20}, // 若有毛,则是哺乳类
	{{1,-1},20}, // 若产奶,则是哺乳类
	{{2,-1},21},
	{{3,4,-1},21},
	{{20,5,-1},22},
	{{6,7,8,-1},22},
	{{20,8,-1},23},
	{{20,9,-1},23},
	{{21,17,18,16,-1},24},
	{{21,19,-1},25}, // 如果是鸟类且善飞,则是海燕
	{{21,14,15,16,-1},26},
	{{23,13,-1},27},
	{{23,14,15,12,-1},28},
	{{22,11,13,-1},29},
	{{22,11,12,-1},30} // 若是肉食类且黄褐色且有斑点, 则是金钱豹
};

2. 推理机

推理机的实现

当用户选择某个特征的时候都会调用判断程序,判断程序首先会将用户选择的那个特征「置 1」或者「置 0」,但是因为当用户将某个特征置为 0 之后,由这个特征所推导出的结论也应该取消,所以需要删除之前所有的推论,重新推导。

然后是借用 JavaScript 数组的「reduce」特性遍历所有规则中的条件并保存推导过程。关于 JavaScript 数组的 reduce 用法可以参考官方文档

在推导的过程中我们将推导的过程保存在了 process 变量里面,这样我们可以清晰地看到这个「专家」的思考过程。

activate (ind) {
  this.result[ind] = !this.result[ind]
  // 对非用户选择的数据清零
  this.result = this.result.map((value, index) => index >= 20 ? false : value )
  const reducer = (accumulator, currentValue) => accumulator && this.result[currentValue];
  const reduce_word =  (accumulator, currentValue) => accumulator + this.features[currentValue] + '且';
  this.process = []
  for (var item of this.rules) {
    if (item.conditions.reduce(reducer, true)) {
      const word = item.conditions.reduce(reduce_word, '因为').slice(0, -1)
      this.process.push(word + ', 所以可得' + this.features[item.conclusion])
      this.result[item.conclusion] = item.conditions.reduce(reducer, true)
    }
  }
},

规则的序列

在对所有规则进行遍历的过程中,存在这样一个问题,比如有下面两条个规则(不属于上面的规则库):

  1. 如果「长脖子」且是「食草动物」,可推出「长颈鹿」
  2. 如果「有毛」且「有蹄」,可推出「食草动物」

用户的输入条件是:「长脖子、有毛、有蹄」,在顺序遍历规则的时候,第一条规则的条件中,不满足食草动物的条件,所以不能推导出是长颈鹿;当遍历到第二条规则的时候虽然已经推导出是食草动物,但是由于已经遍历完成,所以无法得到该动物是长颈鹿。所以对于所有的规则,应当满足拓扑序列。这里所有的规则正好是满足拓扑序列的。

图示

交互逻辑

先看一下预期的效果:

HTML 代码:不使用 Vue 做可视化的同学可以忽略代码,直接看后面的效果图片;

<template>
  <h2>条件</h2>
  <div class="item-box">
    <div v-for="(item, ind) in features.slice(0, 20)" :key="ind" 
         :class="computeClass(ind)"
         @click="activate(ind)"> {{ item }}<br>( {{ ind }} )
    </div>
  </div>
  <h2>推论</h2>
  <div class="item-box">
    <div v-for="(item, ind) in features.slice(20)" :key="item" 
         class="active"
         v-if="conclusion[ind]"> {{ item }}<br>( {{ ind+20 }} )
    </div>
  </div>  
  <h2>过程</h2>
  <p v-for="line in process" class="line">{{ line }} </p>
</template>

用户的逻辑就是点击上面的条件可以「选中」该条件或者「取消选中」,然后系统会根据用户的选择给出推论,同时会将推导的过程放在最后面显示出来。点此 体验

总结及参考链接

下面是个人的看法,从某种角度上感觉这个专家系统很落后,很没有用处,不就是各种判断吗,没什么了不起的。但是仔细想一想,人的大脑再怎么厉害,不也就是根据以往的经验来对当前的情况进行判断的吗。之所以感觉上面的专家系统太笨,是因为这里的知识库以及规则太少了,历史上还有很多成功的专家系统的案例的。

[1] 专家系统 - 维基百科

猜你喜欢

转载自blog.csdn.net/jaykm/article/details/106057109