-
本文由来
[看论文,定量与定性之间评价关系里经常有人用到云模型,看了后觉得,还真是给一个量化指标就能输出分类的确定度,python代码照着MATLAB写的,自从用了python后很少用MATLAB了,留下来省的以后用的时候再找MATLAB脚本了。]
2018年写小论文期间,由于计算及绘图需要,写了本文代码,随后放到此博客,避免遗忘,且希望能帮到需要的人。代码并无任何创新,纯粹是云理论的python实现。2018至今,经过多位同学的咨询提问,本文代码得以逐步美化,在此表示感谢。
------------------------------------------------分割线------------------------------------------------------------------
有位同学需要matlab版本的代码,想了想在学校大多数人也不愿意折腾python,matlab那么方便干嘛不用,于是花了个把小时写了个matlab版本的代码,放在python代码后面了,请拿去使用,不用谢。
------------------------------------------------分割线 python代码----------------------------------------------------
-
头文件及基础配置
引入:
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) # 延时关闭,以便开启多个绘图窗口,须在程序最后执行
------------------------------------------------分割线 matlab代码-----------------------------------------------------
clear;
clc;
% 生成3个1维云模型数据
cloud1 = generate_cloud_model(5,1,0.01,200,'云图1','r','o');
cloud2 = generate_cloud_model(9,3,0.01,200,'云图2','b','o');
cloud3 = generate_cloud_model(-2,2,0.01,200,'云图3','m','o');
% 绘制刚才生成的2个1维云模型
plot_cloud_models({cloud1,cloud2,cloud3},'这是一张1维云图','指标1','隶属度');
% 生成3个2维云模型数据
cloud4 = generate_2d_cloud_model([5 5],[2 4],[0.01 0.001],200,'云图4','r','*');
cloud5 = generate_2d_cloud_model([15 10],[4 2],[0.01 0.001],200,'云图5','b','*');
cloud6 = generate_2d_cloud_model([10 2],[1 3],[0.01 0.001],200,'云图6','m','*');
% 绘制刚才生成的2个2维云模型
plot_2d_cloud_models({cloud4,cloud5,cloud6},'这是一张2维云图','指标1','指标2','隶属度');
%% 生成1组1维云模型数据
function result = generate_cloud_model(Ex, En, He, n, label, color,marker)
% Ex, 云模型的期望,是1维向量
% En, 云模型的熵,是1维向量
% He, 云模型的超熵,是1维向量
% n, 云模型数据点数量,是1维向量
% label, 云模型图例标签,是1维向量
% color, 云模型绘图时的点的颜色,是1维向量
% marker,云模型绘图时的点的形状,是1维向量
Y = zeros(n,1);
X = normrnd(En,He,n,1);
for i=1:n
Enn = X(i);
X(i) = normrnd(Ex,abs(Enn),1,1);
Y(i) = power(exp(1),-(X(i) - Ex) * (X(i) - Ex) / (2 * Enn * Enn));
end
result = {X,Y,color,marker,label};
end
%% 生成1组2维云模型数据
function result = generate_2d_cloud_model(Ex, En, He, n, label, color,marker)
% Ex, 云模型的期望,是2维向量
% En, 云模型的熵,是2维向量
% He, 云模型的超熵,是2维向量
% n, 云模型数据点数量,是1维向量
% label, 云模型图例标签,是1维向量
% color, 云模型绘图时的点的颜色,是1维向量
% marker,云模型绘图时的点的形状,是1维向量
Y = zeros(n,1);
X1 = normrnd(En(1),He(1),n,1);
X2 = normrnd(En(2),He(2),n,1);
for i=1:n
Enn1 = X1(i);
X1(i) = normrnd(Ex(1),abs(Enn1),1,1);
Enn2 = X2(i);
X2(i) = normrnd(Ex(2),abs(Enn2),1,1);
Y(i) = power(exp(1),-(X1(i) - Ex(1)) * (X1(i) - Ex(1)) / (2 * Enn1 * Enn1)-(X2(i) - Ex(2)) * (X2(i) - Ex(2)) / (2 * Enn2 * Enn2));
end
result = {X1,X2,Y,color,marker,label};
end
%% 画多个1维云模型图,云模型数据由generate函数生成
function plot_cloud_models(models,model_title,x_label,y_label)
% models,包含了多组云模型数据,在本函数中将这些云模型数据画出来
% model_title,要绘制图的title
% x_label,要绘制图的x轴标签
% y_label,要绘制图的y轴标签
model_count = length(models);
if(model_count == 0)
return;
end
labels = strings(1,model_count);
figure;
hold on;
for i=1:model_count
cur_model = models(i);
cur_model = cur_model{1};
X = cur_model{1};
Y = cur_model{2};
color = cur_model{3};
marker = cur_model{4};
labels(i) = cur_model{5};
scatter(X,Y,color,marker);
end
legend(labels);
title(model_title)
xlabel(x_label)
ylabel(y_label)
grid on;
view(2)
hold off;
end
%% 画多个2维云模型图,云模型数据由generate函数生成
function plot_2d_cloud_models(models,model_title,x_label,y_label,z_label)
% models,包含了多组云模型数据,在本函数中将这些云模型数据画出来
% model_title,要绘制图的title
% x_label,要绘制图的x轴标签
% y_label,要绘制图的y轴标签
% z_label,要绘制图的z轴标签
model_count = length(models);
if(model_count == 0)
return;
end
labels = strings(1,model_count);
figure;
hold on;
for i=1:model_count
cur_model = models(i);
cur_model = cur_model{1};
X = cur_model{1};
Y = cur_model{2};
Z = cur_model{3};
color = cur_model{4};
marker = cur_model{5};
labels(i) = cur_model{6};
scatter3(X,Y,Z,color,marker);
end
legend(labels);
title(model_title)
xlabel(x_label)
ylabel(y_label)
zlabel(z_label)
grid on;
view(3)
hold off;
end
matlab绘图结果:
-
落款
如有疑问,评论留言或imtht.cn@gmail.com,知无不言,祝各位早日交稿费。