写在前面
模糊数学是国内外许多工学、管理学研究生以上的选修甚至必修课程。但对于非数学专业而言,掌握模糊数学的各种计算方法、了解各种方法的用途(应用场景)其实要比理解模糊数学的“数学”理论要重要得多。目前在Matlab等数学工具中其实也有相应的模糊数学工具箱(参见:Fuzzy Logic ToolboxFuMatlab Fuzzy Logic工具箱),但这些专业的工具中其实集成的都是比较复杂的方法,比如模糊控制一类。另外以前也有一些学者开发过基于C的工具箱,但对于非计算机、信息类专业而言,C库实在也太麻烦。
相比之下,Python对于绝大多数非计算机、信息类专业的学生和研究人员而言都要简单很多,并且也可以作为长期使用的一门工具语言。
当然,我们很懒!所以就去找了一圈写好的模糊数学库,也就是本文要介绍的这个库-scikit-fuzzy。
一、概览和安装
项目主页:User Guide - skfuzzy v0.2 docs
Github主页:scikit-fuzzy/scikit-fuzzy
在这两个主页上其实看不出什么有价值的内容,需要点进相关的页面才能看清楚。最主要的功能介绍在API documentation 和User Guide上。
主要模块:
- Module:cluster :模糊聚类
- Module:control:模糊控制
- Module:defuzzify:模糊化与去模糊化
- Module:filters :模糊滤波
- Module:fuzzymath :模糊数学基础内容
- Module:image:图象相关内容
- Module:`intervals` :区间数与模糊数
- Module:membership:模糊隶属度函数
另外,这个库比较不地道的一点是这些模块虽然分开放了,但其实又全部放在总的根目录skfuzzy
下。 所有方法都是以函数的形式写的,因此在用的时候只需要全部导入就行。
安装方法与依赖:
- 主要依赖项:
- NumPy >= 1.6
- SciPy >= 0.9
- NetworkX >= 1.9
- Pip安装:
$ pip install -U scikit-fuzzy
注意:这安装之前一定要检查是否装有Nump和Scipy,至于NetworkX似乎并不一定要用(当然由于我们目前也只用到了5、7、8三个模块)。
2020.11.10注:
另外,安装这个库之前最好更新一下setup_tools。原因也不多说了,只管在安装前运行一次:python -m pip install --upgrade setuptools
如果很久没有更新过pip
,那么最好也更新一下:python -m pip install --upgrade pip
对于网速存在问题的同学可以使用本地安装,或者直接拷贝完整代码。相应的方法自行度娘即可。
二、模糊集合的表示方法
模糊数学的研究对象就是模糊集,那么模糊数学的库的操作对象其实也就是模糊集。在我们的模糊数学课程笔记 里介绍过这样的两种表示方法:
这两种表示法是最容易在计算机里实现的。而在skfuzzy
库里,都是直接用numpy
的ndarray
或者list
来直接表示的。而通常我们推荐直接使用numpy
的ndarray
,因为这样也方便我们对它们进行其它的操作。
三、一些常用方法简单举例
下面我们来举几个例子说明它的用法:
- 求两个模糊集的交集--
fuzzy_and
:
from skfuzzy import *# 模糊集的元素
x = np.array([1,2,3])
# 对应元素的隶属度
mf_x = np.array([0.1,0.2,0.3])# 模糊集的元素
y = np.array([1,2,3])
# 对应元素的隶属度
mf_y = np.array([0.1,0.2,0.3])+0.3# 上述两个模糊集的交集
fuzzy_and(x,mf_x,y,mf_y)
Out[22]: (array([1, 2, 3]), array([0.1, 0.2, 0.3]))
- 求两个模糊集的并集--
fuzzy_or
:
fuzzy_or(x,mf_x,y,mf_y)
Out[24]: (array([1, 2, 3]), array([0.4, 0.5, 0.6]))
- 区间数的四则运算
我们以笔记 八、模糊数及其运算性质 中的区间数为例:
# 定义两个区间数。其实就是两个区间,本质上是列表。
I = [1,3]
J = [2,5]# 加
addval(I,J)
Out[27]: array([3, 8])# 减
subval(I,J)
Out[28]: array([-4, 1], dtype=int32)# 乘
multval(I,J)
Out[29]: array([ 2, 15], dtype=int32)# 除
divval(I,J)
Out[30]: array([0.2, 1.5])
对比一下,结果完全一致。
- 模糊数的四则运算
在我们的笔记 八、模糊数及其运算性质 中提到过,模糊数其实就是一种特殊的模糊集,因此它的表示方法和模糊集其实完全一样。这里我们仍然用笔记中的例子来做一下测试:
笔记中我们给出了加、减、乘的结果:
实现代码:
# 例子中的模糊数“2”
x = [1,2,3]
mfx = [0.4,1,0.7]# 例子中的模糊数“3”
y = [2,3,4]
mfy = [0.5,1,0.6]# 加
fuzzy_add(x,mfx,y,mfy)
Out[36]: (array([3., 4., 5., 6., 7.]), array([0.4, 0.5, 1. , 0.7, 0.6]))# 减
fuzzy_sub(x,mfx,y,mfy)
Out[37]: (array([-3., -2., -1., 0., 1.]), array([0.4, 0.6, 1. , 0.7, 0.5]))# 乘
fuzzy_mult(x,mfx,y,mfy)
Out[38]:
(array([ 2., 3., 4., 6., 8., 9., 12.]),array([0.4, 0.4, 0.5, 1. , 0.6, 0.7, 0.6]))
当然我们还可以算出“除”的结果:
fuzzy_div(x,mfx,y,mfy)
Out[39]:
(array([0.25 , 0.33333333, 0.5 , 0.66666667, 0.75 ,1. , 1.5 ]),array([0.4, 0.4, 0.6, 1. , 0.6, 0.7, 0.5]))
注意:这个例子中我们实际上是用list
来表示的模糊数。也就是说,list
和ndarray
其实都是支持的。
三、注意事项
1、模糊子集的元素只支持数字
先看例子:
a = ['x1','x2']
b = ['x1','x3']mfa = [0.1,0.2]
mfb = [0.2,0.3]fuzzy_and(a,mfa,b,mfb)
---------------------------------------------------------------------------
UFuncTypeError Traceback (most recent call last)
<ipython-input-51-5adc794dbb9c> in <module>
----> 1 fuzzy_and(a,mfa,b,mfb)d:programdataanaconda3envstoolslibsite-packagesskfuzzyfuzzymathfuzzy_logic.py in fuzzy_and(x, mfx, y, mfy)101 """102 # Check if universes are the same
--> 103 return fuzzy_norm(x, mfx, y, mfy, norm=np.fmin)104 105 d:programdataanaconda3envstoolslibsite-packagesskfuzzyfuzzymathfuzzy_logic.py in fuzzy_norm(x, mfx, y, mfy, norm)72 73 if not sameuniverse:
---> 74 z, mfx2, mfy2 = _resampleuniverse(x, mfx, y, mfy)75 76 return z, norm(mfx2, mfy2)d:programdataanaconda3envstoolslibsite-packagesskfuzzyfuzzymathfuzzy_logic.py in _resampleuniverse(x, mfx, y, mfy)14 15 """
---> 16 minstep = np.asarray([np.diff(x).min(), np.diff(y).min()]).min()17 18 mi = min(x.min(), y.min())<__array_function__ internals> in diff(*args, **kwargs)d:programdataanaconda3envstoolslibsite-packagesnumpylibfunction_base.py in diff(a, n, axis, prepend, append)1267 op = not_equal if a.dtype == np.bool_ else subtract1268 for _ in range(n):
-> 1269 a = op(a[slice1], a[slice2])1270 1271 return aUFuncTypeError: ufunc 'subtract' did not contain a loop with signature matching types (dtype('<U2'), dtype('<U2')) -> dtype('<U2')
这个例子里我们试图实现两个模糊子集:
fuzzy_and
就报错了。说明在这个库里,并不支持数字以外的模糊集元素。 事实上,在模糊集的基本操作中,还需要模糊集具有shape
属性,因此此时如果使用list
来表示模糊集就会出问题。这也是我们更加推荐使用ndarray
来表示模糊集的重要原因之一。
2、模糊子集基本操作并不完善
仍然以上述两个模糊子集为例
a = np.array([1,2])
b = np.array([2,3])
mfa = np.array([0.1,0.2])
mfb = np.array([0.2,0.3])# 交
fuzzy_and(a,mfa,b,mfb)
Out[64]: (array([1, 2]), array([0.1, 0.2]))# 并
fuzzy_or(a,mfa,b,mfb)
Out[63]: (array([1, 2]), array([0.2, 0.2]))
注意! 模糊子集的交集是对应元素取小,并集则是对应元素取大。但从这个结果上来看,程度并没有将两个子集中的元素 1,2,3
认成3个不同的元素,而只是将a
,b
中相同位置的元素认定成了同一个元素,并且是以第一个集合中的元素为主进行操作的。
这一设定显然并不符合模糊数学中对交、并的定义。因此在使用时要小心。
四、总体评价
1、功能基本完善。因为我们目前笔记中的内容几乎全部包含。另外还有一些其它主流库中的内容也包含,例如模糊聚类(和基本聚类有所区别)、模糊控制等(不过高端的计算操作目前我们认为并不值得信任)。
2、文档可读性:算不上好!
比如这里:fuzzy_add
是指模糊数的加法,这里说"a,b是两个模糊集",而根据我们刚刚的测试很清楚一点的是:这里的a
,b
其实就是元素x
和y
对应的隶属度。它下面对应的fuzzy_and
函数就是这样写的。这个库的文档里,表示相同意思的变量被标成不同的符号和不同的说明的情况很多! 如果没有充分的模糊数学基础加上一定的经验的话,很容易被迷惑。
3、维护不算积极
从它的发布历史来看,库的作者从2016年首次发布这个库,到2019年为止每年下半年更新一次。并且更新的内容也不算太完整。(不过从这个规律来看,感觉这可能是某个上这课的老师开发的。可能刚好每年上完一次,就发现一些问题更新一次)。
综上:
1、这个库总体来说能用,
2、对于不涉及过于复杂的模糊数学的操作而言,也基本够用。
3、有一些小问题,但也不太影响总体的功能性。另外在模糊集的处理上还有待提高,没有对模糊子集这个对象进行单独封装是个很大的问题!
4、目前基于这个库的基本功能,其实可以完整实现我们课程笔记中的所有操作!
所以,这个事儿我们应该会有后续!~ 敬请期待~
关注我们获取更多有趣有用的内容:
- 更新2020-11-06:更新模糊动态聚类,关注公粽号:mathit 搜历史消息“模糊动态聚类”即可查阅。