本文由来
看论文,定量与定性之间评价关系里经常有人用到云模型,看了后觉得,还真是给一个量化指标就能输出分类的确定度,python代码照着MATLAB写的,自从用了python后很少用MATLAB了,留下来省的以后用的时候再找MATLAB脚本了。
2018年写小论文期间,由于计算及绘图需要,写了本文代码,随后放到此博客,避免遗忘,且希望能帮到需要的人。代码并无任何创新,纯粹是云理论的python实现。2018至今,经过多位同学的咨询提问,本文代码得以逐步美化,在此表示感谢。
------------------------------------------------分割线------------------------------------------------------------------
头文件及基础配置
引入:
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from time import time,clock
添加字段,以再matplotlib中显示中文字符
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.ion() # 关闭阻塞模式
------------------------------------------------分割线------------------------------------------------------------------
一维云模型
def plot_cloud_model(Ex, En, He, n, ax, label='', color = 'r',marker = 'o'):
"""该函数每次画1个云图
Args:
Ex (float): 期望
En (float): 熵
He (float): 超熵
n (int): 云滴数量
ax (Axes): 画布,云图将绘制到指定画布上
label (str, optional): 云图名称,会显示在图例中,默认为空
color (str, optional): 云图颜色,默认'r'代表红色
marker (str, optional): 数据点显示符号,默认显示一个圆圈
"""
Y = np.zeros((1, n))
np.random.seed(int(np.random.random()*100))
X= np.random.normal(loc=En, scale=He, size=n)
Y = Y[0]
for i in range(n):
np.random.seed(int(np.random.random()*100) + i + 1)
Enn = X[i]
X[i] = np.random.normal(loc=Ex, scale=np.abs(Enn), size=1)
Y[i] = np.exp(-(X[i] - Ex) * (X[i] - Ex) / (2 * Enn * Enn))
ax.scatter(X, Y, s=10, alpha=0.5, c=color, marker=marker, label=label)
执行:
if __name__ =='__main__':
fig = plt.figure(len(plt.get_fignums()))
ax = fig.add_subplot(111) #创建画布,画布句柄为ax
title = '设置你的标题'
ax.set_title(title)#在ax指向的画布上绘图
ax.set_xlabel('期望')
ax.set_ylabel('隶属度')
ax.grid(True)
plot_cloud_model(1.5, 0.61, 0.1, 500, ax,'云图1','r','o')
plot_cloud_model(2.0, 0.33, 0.1, 500, ax,'云图2','g','x')
plot_cloud_model(-1, 0.8, 0.1, 500, ax,'云图3','b','*')
ax.legend(loc='best')
plt.show()
plt.pause(3600) # 延时关闭,以便开启多个绘图窗口,须在程序最后执行
结果:
------------------------------------------------分割线------------------------------------------------------------------
二维云模型
def plot_2d_cloud_model(Ex, En, He, n, ax, label='', color = 'r',marker = 'o'):
"""该函数每次画1个云图
Args:
Ex ([float,float]): 期望,二维数组
En ([float,float]): 熵,二维数组
He ([float,float]): 超熵,二维数组
n (int): 云滴数量
ax (Axes): 画布,必须为3d画布,云图将绘制到指定画布上
label (str, optional): 云图名称,会显示在图例中,默认为空
color (str, optional): 云图颜色,默认'r'代表红色
marker (str, optional): 数据点显示符号,默认显示一个圆圈
"""
Y = np.zeros((1, n))
np.random.seed(int(np.random.random()*100))
X0 = np.random.normal(loc=En[0], scale=He[0], size=n)
Y = Y[0]
np.random.seed(int(np.random.random()*100)+1)
X1 = np.random.normal(loc=En[1], scale=He[1], size=n)
for i in range(n):
Enn0 = X0[i]
np.random.seed(int(np.random.random()*100)+i)
X0[i] = np.random.normal(loc=Ex[0], scale=np.abs(Enn0), size=1)
Enn1 = X1[i]
np.random.seed(int(np.random.random()*100)+i+1)
X1[i] = np.random.normal(loc=Ex[1], scale=np.abs(Enn1), size=1)
Y[i] = np.exp(-(X0[i] - Ex[0]) * (X0[i] - Ex[0]) / (2 * Enn0 * Enn0)-(X1[i] - Ex[1]) * (X1[i] - Ex[1]) / (2 * Enn1 * Enn1))
ax.scatter(X0, X1, Y, s=10, alpha=0.5, c=color, marker=marker,label=label)
执行:
if __name__ =='__main__':
fig_3d = plt.figure(len(plt.get_fignums()))
fig_3d = fig_3d.add_subplot(111, projection='3d') #创建三维画布,画布句柄为ax_3d
title = '设置你的标题'
fig_3d.set_title(title)#在ax_3d指向的画布上绘图
fig_3d.set_xlabel('期望1')
fig_3d.set_ylabel('期望2')
fig_3d.set_zlabel('隶属度')
fig_3d.grid(True)
plot_2d_cloud_model([1.5,2], [0.61,0.2], [0.1,0.1], 2000, fig_3d,'云图1','r','o')
plot_2d_cloud_model([2.0,2.5], [0.33,0.5], [0.1,0.1], 2000, fig_3d,'云图2','g','x')
plot_2d_cloud_model([-1,1], [0.8,0.1], [0.1,0.1], 2000, fig_3d,'云图3','b','*')
fig_3d.legend(loc='best')
plt.show()
plt.pause(3600) # 延时关闭,以便开启多个绘图窗口,须在程序最后执行
结果:
------------------------------------------------分割线------------------------------------------------------------------
二维可分割云模型
def plot_2d_trim_cloud_model(Ex, En, He, n, ax, trim_panel=[[1.5,0.5,0],[0.5,1.5,0],[0.5,1.5,1],1],label='', color = 'r',marker = 'o'):
"""该函数每次画1个云图
Args:
Ex ([float,float]): 期望,二维数组
En ([float,float]): 熵,二维数组
He ([float,float]): 超熵,二维数组
n (int): 云滴数量
ax (Axes): 画布,必须为3d画布,云图将绘制到指定画布上
trim_panel:分割面,数组的前三个元素为分割面上的三个点,最后一位>0时筛选出分割面以上的点,<0时筛选出分割面以下的点
label (str, optional): 云图名称,会显示在图例中,默认为空
color (str, optional): 云图颜色,默认'r'代表红色
marker (str, optional): 数据点显示符号,默认显示一个圆圈
"""
#确定分割panel的四个参数
a=(trim_panel[1][1]-trim_panel[0][1])*(trim_panel[2][2]-trim_panel[0][2])-(trim_panel[1][2]-trim_panel[0][2])*(trim_panel[2][1]-trim_panel[0][1])
b=(trim_panel[1][2]-trim_panel[0][2])*(trim_panel[2][0]-trim_panel[0][0])-(trim_panel[1][0]-trim_panel[0][0])*(trim_panel[2][2]-trim_panel[0][2])
c=(trim_panel[1][0]-trim_panel[0][0])*(trim_panel[2][1]-trim_panel[0][1])-(trim_panel[1][1]-trim_panel[0][1])*(trim_panel[2][0]-trim_panel[0][0])
d=-(a*trim_panel[0][0]+b*trim_panel[0][1]+c*trim_panel[0][2])
Y = np.zeros((1, n))
np.random.seed(int(np.random.random()*100))
X0 = np.random.normal(loc=En[0], scale=He[0], size=n)
Y = Y[0]
np.random.seed(int(np.random.random()*100)+1)
X1 = np.random.normal(loc=En[1], scale=He[1], size=n)
for i in range(n):
Enn0 = X0[i]
np.random.seed(int(np.random.random()*100)+i)
X0[i] = np.random.normal(loc=Ex[0], scale=np.abs(Enn0), size=1)
Enn1 = X1[i]
np.random.seed(int(np.random.random()*100)+i+1)
X1[i] = np.random.normal(loc=Ex[1], scale=np.abs(Enn1), size=1)
Y[i] = np.exp(-(X0[i] - Ex[0]) * (X0[i] - Ex[0]) / (2 * Enn0 * Enn0)-(X1[i] - Ex[1]) * (X1[i] - Ex[1]) / (2 * Enn1 * Enn1))
#筛选出分割面一侧的点
Selected_X0 = []
Selected_X1 = []
Selected_Y = []
if(trim_panel[3]>0):
for i in range(n):
if((a*X0[i]+b*X1[i]+c*Y[i]+d)>=0):
Selected_X0.append(X0[i])
Selected_X1.append(X1[i])
Selected_Y.append(Y[i])
else:
for i in range(n):
if((a*X0[i]+b*X1[i]+c*Y[i]+d)<0):
Selected_X0.append(X0[i])
Selected_X1.append(X1[i])
Selected_Y.append(Y[i])
ax.scatter(Selected_X0, Selected_X1, Selected_Y, s=10, alpha=0.5, c=color, marker=marker,label=label)
执行:
if __name__ =='__main__':
fig_3d_trim = plt.figure(len(plt.get_fignums()))
ax_3d_trim = fig_3d_trim.add_subplot(111, projection='3d') #创建三维画布,画布句柄为ax_3d
title = '设置你的标题'
ax_3d_trim.set_title(title)#在ax_3d指向的画布上绘图
ax_3d_trim.set_xlabel('期望1')
ax_3d_trim.set_ylabel('期望2')
ax_3d_trim.set_zlabel('隶属度')
ax_3d_trim.grid(True)
trim_panel = [[2,2,0],[0.5,1.5,0],[0.5,1.5,1],1]#定义一个分割面
plot_2d_trim_cloud_model([1.5,2], [0.61,0.2], [0.1,0.1], 2000, ax_3d_trim,trim_panel,'云图1','r','o')
plot_2d_trim_cloud_model([2.0,2.5], [0.33,0.5], [0.1,0.1], 2000, ax_3d_trim,trim_panel,'云图2','g','x')
plot_2d_trim_cloud_model([-1,1], [0.8,0.1], [0.1,0.1], 2000, ax_3d_trim,trim_panel,'云图3','b','*')
ax_3d_trim.legend(loc='best')
plt.show()
plt.pause(3600) # 延时关闭,以便开启多个绘图窗口,须在程序最后执行
结果:
------------------------------------------------分割线------------------------------------------------------------------
代码汇总
import numpy as np
import matplotlib.pyplot as plt
from time import perf_counter
plt.rcParams['font.sans-serif'] = ['SimHei'] #运行配置参数中的字体(font)为黑体(simHei)
plt.rcParams['axes.unicode_minus'] = False #运行配置参数总的轴(axes)正常显示正负号(minus)
plt.ion() # 关闭阻塞模式
def plot_cloud_model(Ex, En, He, n, ax, label='', color = 'r',marker = 'o'):
"""该函数每次画1个云图
Args:
Ex (float): 期望
En (float): 熵
He (float): 超熵
n (int): 云滴数量
ax (Axes): 画布,云图将绘制到指定画布上
label (str, optional): 云图名称,会显示在图例中,默认为空
color (str, optional): 云图颜色,默认'r'代表红色
marker (str, optional): 数据点显示符号,默认显示一个圆圈
"""
Y = np.zeros((1, n))
np.random.seed(int(np.random.random()*100))
X= np.random.normal(loc=En, scale=He, size=n)
Y = Y[0]
for i in range(n):
np.random.seed(int(np.random.random()*100) + i + 1)
Enn = X[i]
X[i] = np.random.normal(loc=Ex, scale=np.abs(Enn), size=1)
Y[i] = np.exp(-(X[i] - Ex) * (X[i] - Ex) / (2 * Enn * Enn))
ax.scatter(X, Y, s=10, alpha=0.5, c=color, marker=marker, label=label)
def plot_2d_cloud_model(Ex, En, He, n, ax, label='', color = 'r',marker = 'o'):
"""该函数每次画1个云图
Args:
Ex ([float,float]): 期望,二维数组
En ([float,float]): 熵,二维数组
He ([float,float]): 超熵,二维数组
n (int): 云滴数量
ax (Axes): 画布,必须为3d画布,云图将绘制到指定画布上
label (str, optional): 云图名称,会显示在图例中,默认为空
color (str, optional): 云图颜色,默认'r'代表红色
marker (str, optional): 数据点显示符号,默认显示一个圆圈
"""
Y = np.zeros((1, n))
np.random.seed(int(np.random.random()*100))
X0 = np.random.normal(loc=En[0], scale=He[0], size=n)
Y = Y[0]
np.random.seed(int(np.random.random()*100)+1)
X1 = np.random.normal(loc=En[1], scale=He[1], size=n)
for i in range(n):
Enn0 = X0[i]
np.random.seed(int(np.random.random()*100)+i)
X0[i] = np.random.normal(loc=Ex[0], scale=np.abs(Enn0), size=1)
Enn1 = X1[i]
np.random.seed(int(np.random.random()*100)+i+1)
X1[i] = np.random.normal(loc=Ex[1], scale=np.abs(Enn1), size=1)
Y[i] = np.exp(-(X0[i] - Ex[0]) * (X0[i] - Ex[0]) / (2 * Enn0 * Enn0)-(X1[i] - Ex[1]) * (X1[i] - Ex[1]) / (2 * Enn1 * Enn1))
ax.scatter(X0, X1, Y, s=10, alpha=0.5, c=color, marker=marker,label=label)
def plot_2d_trim_cloud_model(Ex, En, He, n, ax, trim_panel=[[1.5,0.5,0],[0.5,1.5,0],[0.5,1.5,1],1],label='', color = 'r',marker = 'o'):
"""该函数每次画1个云图
Args:
Ex ([float,float]): 期望,二维数组
En ([float,float]): 熵,二维数组
He ([float,float]): 超熵,二维数组
n (int): 云滴数量
ax (Axes): 画布,必须为3d画布,云图将绘制到指定画布上
trim_panel:分割面,数组的前三个元素为分割面上的三个点,最后一位>0时筛选出分割面以上的点,<0时筛选出分割面以下的点
label (str, optional): 云图名称,会显示在图例中,默认为空
color (str, optional): 云图颜色,默认'r'代表红色
marker (str, optional): 数据点显示符号,默认显示一个圆圈
"""
#确定分割panel的四个参数
a=(trim_panel[1][1]-trim_panel[0][1])*(trim_panel[2][2]-trim_panel[0][2])-(trim_panel[1][2]-trim_panel[0][2])*(trim_panel[2][1]-trim_panel[0][1])
b=(trim_panel[1][2]-trim_panel[0][2])*(trim_panel[2][0]-trim_panel[0][0])-(trim_panel[1][0]-trim_panel[0][0])*(trim_panel[2][2]-trim_panel[0][2])
c=(trim_panel[1][0]-trim_panel[0][0])*(trim_panel[2][1]-trim_panel[0][1])-(trim_panel[1][1]-trim_panel[0][1])*(trim_panel[2][0]-trim_panel[0][0])
d=-(a*trim_panel[0][0]+b*trim_panel[0][1]+c*trim_panel[0][2])
Y = np.zeros((1, n))
np.random.seed(int(np.random.random()*100))
X0 = np.random.normal(loc=En[0], scale=He[0], size=n)
Y = Y[0]
np.random.seed(int(np.random.random()*100)+1)
X1 = np.random.normal(loc=En[1], scale=He[1], size=n)
for i in range(n):
Enn0 = X0[i]
np.random.seed(int(np.random.random()*100)+i)
X0[i] = np.random.normal(loc=Ex[0], scale=np.abs(Enn0), size=1)
Enn1 = X1[i]
np.random.seed(int(np.random.random()*100)+i+1)
X1[i] = np.random.normal(loc=Ex[1], scale=np.abs(Enn1), size=1)
Y[i] = np.exp(-(X0[i] - Ex[0]) * (X0[i] - Ex[0]) / (2 * Enn0 * Enn0)-(X1[i] - Ex[1]) * (X1[i] - Ex[1]) / (2 * Enn1 * Enn1))
#筛选出分割面一侧的点
Selected_X0 = []
Selected_X1 = []
Selected_Y = []
if(trim_panel[3]>0):
for i in range(n):
if((a*X0[i]+b*X1[i]+c*Y[i]+d)>=0):
Selected_X0.append(X0[i])
Selected_X1.append(X1[i])
Selected_Y.append(Y[i])
else:
for i in range(n):
if((a*X0[i]+b*X1[i]+c*Y[i]+d)<0):
Selected_X0.append(X0[i])
Selected_X1.append(X1[i])
Selected_Y.append(Y[i])
ax.scatter(Selected_X0, Selected_X1, Selected_Y, s=10, alpha=0.5, c=color, marker=marker,label=label)
if __name__ =='__main__':
# 画二维图
fig = plt.figure(len(plt.get_fignums()))
ax = fig.add_subplot(111) #创建画布,画布句柄为ax
title = '设置你的标题'
ax.set_title(title)#在ax指向的画布上绘图
ax.set_xlabel('期望')
ax.set_ylabel('隶属度')
ax.grid(True)
plot_cloud_model(1.5, 0.61, 0.1, 500, ax,'云图1','r','o')
plot_cloud_model(2.0, 0.33, 0.1, 500, ax,'云图2','g','x')
plot_cloud_model(-1, 0.8, 0.1, 500, ax,'云图3','b','*')
ax.legend(loc='best')
# 画三维图
fig_3d = plt.figure(len(plt.get_fignums()))
ax_3d = fig_3d.add_subplot(111, projection='3d') #创建三维画布,画布句柄为ax_3d
title = '设置你的标题'
ax_3d.set_title(title)#在ax_3d指向的画布上绘图
ax_3d.set_xlabel('期望1')
ax_3d.set_ylabel('期望2')
ax_3d.set_zlabel('隶属度')
ax_3d.grid(True)
plot_2d_cloud_model([1.5,2], [0.61,0.2], [0.1,0.1], 2000, ax_3d,'云图1','r','o')
plot_2d_cloud_model([2.0,2.5], [0.33,0.5], [0.1,0.1], 2000, ax_3d,'云图2','g','x')
plot_2d_cloud_model([-1,1], [0.8,0.1], [0.1,0.1], 2000, ax_3d,'云图3','b','*')
ax_3d.legend(loc='best')
# 画带分割面的三维图
fig_3d_trim = plt.figure(len(plt.get_fignums()))
ax_3d_trim = fig_3d_trim.add_subplot(111, projection='3d') #创建三维画布,画布句柄为ax_3d
title = '设置你的标题'
ax_3d_trim.set_title(title)#在ax_3d指向的画布上绘图
ax_3d_trim.set_xlabel('期望1')
ax_3d_trim.set_ylabel('期望2')
ax_3d_trim.set_zlabel('隶属度')
ax_3d_trim.grid(True)
trim_panel = [[2,2,0],[0.5,1.5,0],[0.5,1.5,1],1]#定义一个分割面
plot_2d_trim_cloud_model([1.5,2], [0.61,0.2], [0.1,0.1], 2000, ax_3d_trim,trim_panel,'云图1','r','o')
plot_2d_trim_cloud_model([2.0,2.5], [0.33,0.5], [0.1,0.1], 2000, ax_3d_trim,trim_panel,'云图2','g','x')
plot_2d_trim_cloud_model([-1,1], [0.8,0.1], [0.1,0.1], 2000, ax_3d_trim,trim_panel,'云图3','b','*')
ax_3d_trim.legend(loc='best')
plt.show()
plt.pause(3600) # 延时关闭,以便开启多个绘图窗口,须在程序最后执行