Engee 文档
Notebook

用于决策的模糊推理系统

本例演示了创建模糊推理系统的过程。这种系统以模糊集、其成员函数和决策规则的形式将人类推理和专家知识正规化。

安装和连接图书馆

为了创建模糊推理系统,我们将使用名为FuzzyLogic的 Julia 编程语言库。要在 Engee 中安装该库,需要执行以下代码单元:

In [ ]:
Pkg.add(["FuzzyLogic"])
In [ ]:
Pkg.add("FuzzyLogic")

连接已安装的 FuzzyLogic 库:

In [ ]:
using FuzzyLogic

构建模糊推理系统

在下面的代码中,使用 @mamfis 宏构建了一个马姆达尼模糊推理系统。该系统包括为输入和输出变量定义成员函数。

在代码的开头,我们声明了一个小费函数,它需要两个参数:服务和食物。这些变量代表输入数据,将用于估算餐厅顾客想要留下的小费。

对于服务变量,我们使用高斯成员函数定义了三个模糊集:

  • 差,中心为 0,标准偏差为 1.5
  • 好,中心为 5,标准偏差为 1.5
  • 优,中心为 10,标准偏差为 1.5

对于变量 "食物",我们使用梯形隶属度函数定义了两个模糊集:

  • 馊,坐标为(-2,0,1,3)
  • 美味,坐标为(7、9、10、12)

变量 tip 有三个模糊集,分别由三角形隶属度函数定义:

  • 便宜(小),坐标为(0,5,10)
  • 平均值,坐标为(10、15、20)
  • 慷慨,坐标为(20、25、30)

接着,定义模糊逻辑规则,将服务和食物质量与小费联系起来。例如,如果服务不好或食物质量差,小费就会少;如果服务好且食物质量令人满意,小费就会一般,以此类推。

In [ ]:
fis = @mamfis function tipper(service, food)::tip
    service := begin
      domain = 0:10
      poor = GaussianMF(0.0, 1.5)
      good = GaussianMF(5.0, 1.5)
      excellent = GaussianMF(10.0, 1.5)
    end

    food := begin
      domain = 0:10
      rancid = TrapezoidalMF(-2, 0, 1, 3)
      delicious = TrapezoidalMF(7, 9, 10, 12)
    end

    tip := begin
      domain = 0:30
      cheap = TriangularMF(0, 5, 10)
      average = TriangularMF(10, 15, 20)
      generous = TriangularMF(20, 25, 30)
    end

    service == poor || food == rancid --> tip == cheap
    service == good --> tip == average
    service == excellent || food == delicious --> tip == generous
end
Out[0]:
tipper

Inputs:
-------
service ∈ [0, 10] with membership functions:
    poor = GaussianMF{Float64}(0.0, 1.5)
    good = GaussianMF{Float64}(5.0, 1.5)
    excellent = GaussianMF{Float64}(10.0, 1.5)

food ∈ [0, 10] with membership functions:
    rancid = TrapezoidalMF{Int64}(-2, 0, 1, 3)
    delicious = TrapezoidalMF{Int64}(7, 9, 10, 12)


Outputs:
--------
tip ∈ [0, 30] with membership functions:
    cheap = TriangularMF{Int64}(0, 5, 10)
    average = TriangularMF{Int64}(10, 15, 20)
    generous = TriangularMF{Int64}(20, 25, 30)


Inference rules:
----------------
(service is poor ∨ food is rancid) --> tip is cheap
service is good --> tip is average
(service is excellent ∨ food is delicious) --> tip is generous


Settings:
---------
- MinAnd()
- MaxOr()
- MinImplication()
- MaxAggregator()
- CentroidDefuzzifier(100)

以函数fis 的形式使用模糊推理系统为例:

In [ ]:
fis(service=2, food=4)
Out[0]:
1-element Dictionaries.Dictionary{Symbol, Float64}
 :tip │ 7.788531995027619

使用compilefis 生成独立于库的函数:

In [ ]:
fis_ex = compilefis(fis)
Out[0]:
:(function tipper(service, food)
      poor = exp(-((service - 0.0) ^ 2) / 4.5)
      good = exp(-((service - 5.0) ^ 2) / 4.5)
      excellent = exp(-((service - 10.0) ^ 2) / 4.5)
      rancid = max(min((food - -2) / 2, 1, (3 - food) / 2), 0)
      delicious = max(min((food - 7) / 2, 1, (12 - food) / 2), 0)
      ant1 = max(poor, rancid)
      ant2 = good
      ant3 = max(excellent, delicious)
      tip_agg = collect(LinRange{Float64}(0.0, 30.0, 101))
      @inbounds for (i, x) = enumerate(tip_agg)
              cheap = max(min((x - 0) / 5, (10 - x) / 5), 0)
              average = max(min((x - 10) / 5, (20 - x) / 5), 0)
              generous = max(min((x - 20) / 5, (30 - x) / 5), 0)
              tip_agg[i] = max(max(min(ant1, cheap), min(ant2, average)), min(ant3, generous))
          end
      tip = ((2 * sum((mfi * xi for (mfi, xi) = zip(tip_agg, LinRange{Float64}(0.0, 30.0, 101)))) - first(tip_agg) * 0) - last(tip_agg) * 30) / ((2 * sum(tip_agg) - first(tip_agg)) - last(tip_agg))
      return tip
  end)

通过代码生成获得的函数可以写入文件。为此,将格式为Expr 的变量fis_ex 转换为格式为String 的变量,以便进一步写入:

In [ ]:
text_function = string(fis_ex)
Out[0]:
"function tipper(service, food)\n    poor = exp(-((service - 0.0) ^ 2) / 4.5)\n    good = exp(-((service - 5.0) ^ 2) / 4.5)\n    excellent = exp(-((service - 10.0) ^ 2) / 4.5)\n    rancid = max(min((food - -2) / 2, 1, (3 - food) / 2), 0)\n    delicious = max(min((food - 7) / 2" ⋯ 444 bytes ⋯ ", min(ant2, average)), min(ant3, generous))\n        end\n    tip = ((2 * sum((mfi * xi for (mfi, xi) = zip(tip_agg, LinRange{Float64}(0.0, 30.0, 101)))) - first(tip_agg) * 0) - last(tip_agg) * 30) / ((2 * sum(tip_agg) - first(tip_agg)) - last(tip_agg))\n    return tip\nend"

将字符串格式的函数写入文件:

In [ ]:
f = open("fis.jl","w") # создание файла
write(f, text_function) # запись в файл
close(f) # закрытие файла

在 Engee 工作区中使用创建文件中的函数include 定义函数tipper, :

In [ ]:
include("fis.jl")
Out[0]:
tipper (generic function with 1 method)

使用.jl格式文件中的函数。

In [ ]:
tipper(2, 3)
Out[0]:
7.7885319950276175

获得的函数可在其他项目中使用,无需连接FuzzyLogic库。

成员函数的可视化

连接图形可视化库

In [ ]:
using Plots

显示变量的成员函数service

In [ ]:
plot(fis, :service)
Out[0]:

显示变量的成员函数food

In [ ]:
plot(fis, :food)
Out[0]:

显示变量的成员函数tip

In [ ]:
plot(fis, :tip)
Out[0]:

构建响应面

如果一个模糊输出系统有 2 个输入,我们就可以构建其响应曲面。这是一个显示输出数据如何随输入数据变化的曲面:

In [ ]:
# Определяем векторы
s = collect(0:0.2:10) # Вектор s от 0 до 10
f = collect(0:0.2:10) # Вектор f от 0 до 10

# Создаем матрицы значений
tip_matrix = zeros(length(s), length(f))

# Заполняем матрицу значениями отклика
for (i, service) in enumerate(s)
    for (j, food) in enumerate(f)
        tip_matrix[i, j] = tipper(service, food)
    end
end

# Построение поверхности отклика
surface(s, f, tip_matrix, xlabel="Service", ylabel="Food", zlabel="Tip", title="Поверхность отклика", color=:inferno)
Out[0]:

输出

在本示例中,考虑了FuzzyLogic库的功能。它们被用来建立一个模糊推理系统,该系统允许使用模糊逻辑对不确定和不精确的数据进行建模和处理。在决策和计算方面,模糊推理系统将人类推理和专家知识形式化,与传统方法相比,可以在不确定情况下做出更加灵活和适应性更强的决策。