概念
分类是确认同质对象、区分异质对象的思维活动。概念的建立、判断的形成、规律的发现和阐述,都以对象的合理分类为前提。现实世界的事物类别大都是模糊的,宜采用模糊数学方法划分。
模糊聚类分析是依据论域上的模糊等价关系对论域中的对象进行分类的数学方法,是对依据经典等价关系精确分类的这种传统分类方法的推广,基本思想是用相似性尺度来衡量事物之间的亲疏程度,并以此来实现分类。它的实质是根据研究对象本身的属性来构造模糊矩阵,在此基础上根据一定的隶属度来确定其分类关系。
模糊聚类是对于样本的分类,结果是动态的软分类。
步骤
首先导入需要的包:
# -*- coding: utf-8 -*-
import pandas as pd
import numpy as np
import math
from scipy.cluster import hierarchy
import matplotlib.pyplot as plt
1、标准化变换
使用Z-Score
进行标准化变换。由此将不同量级的数据转化为统一量度的Z-Score分值进行比较。
def z_score_std(df):
# z-score标准化处理
return (df-df.mean())/(df.std())
2、建立模糊相似关系
通过欧氏距离建立模糊相似关系。
这里的欧氏距离是样本点空间距离公式,作为n维向量进行处理。也就是说,如果两个标准化后的样本接近一致,则它们之间的欧氏距离会趋近更小的值;如果两样本完全一致,则它们的欧氏距离为零。
最后所使用的实际上是【1-欧氏距离】,定量表示样本“越接近越相似”的这种趋势。相似系数值介于[0, 1]之间,值越接近1,对象之间越相似。
def calc_d(a, b):
# 对dataframe对象计算欧氏距离
distance = 0
for i in range(len(a[0])):
distance += pow((a[0][i]-b[0][i]), 2)
return math.sqrt(distance)
def get_d_mat(row, df):
# 获取d值矩阵
mat_d = np.zeros([row, row])
for i in range(row):
for j in range(row):
mat_d[j][i] = calc_d(np.array(df[i:i+1]), \
np.array(df[j:j+1]))
return mat_d
def get_fuz_sim_mat(mat_d, row):
# 获取模糊相似矩阵
fuz_sim_mat = np.zeros([row, row])
for i in range(row):
for j in range(row):
fuz_sim_mat[i][j] = 1 - (mat_d[i][j]/np.max(mat_d))
return fuz_sim_mat
3、建立等价关系矩阵
通过复合运算,对模糊相似矩阵进行迭代,将模糊相似关系转换为模糊等价关系,建立模糊等价矩阵。
这里需要关注等价关系的“传递性”,保证R = R^2 = R^4 = ...
def isEqual(a,b):
# 判断两矩阵是否完全相等
a,b = np.array(a), np.array(b)
if (a==b).all():
return True
else:
return False
def get_fuz_eql_mat(fuz_smat, row):
# 获得暂时的模糊等价矩阵
fuz_eql_mat = np.zeros([row, row])
for i in range(row):
for j in range(row):
fuz_eql_mat[i][j] = max([min(fuz_smat[i][t], fuz_smat[t][j]) \
for t in range(row)])
return fuz_eql_mat
def final_fuz_eql_mat(a, row, count):
# 最多迭代20次,找到R^k等于R^(2k)的矩阵
count+=1
if(count==20):
return -1
b = get_fuz_eql_mat(a, row)
if(isEqual(a, b)):
return a
else:
return final_fuz_eql_mat(b, row, count)
4、进行模糊聚类
三步走:确定阀值——划分类别——绘制聚类图。
最后确定的分类数根据聚类图确定。如果有专业知识,则按专业知识来划分类数;如果没有,则可以去考察分类数与 λ 的关系。当 λ 变化较大而分类数不变时,该分类比较稳定,可当做最后的分类结果。与该分类数对应的最小 λ 就应该是最后选取的阈值。
def cut_mat(mat, threshold):
return np.where(mat > threshold, 1, 0)
def get_classify_num(array):
return len(np.unique(array, axis=0))
绘制聚类图自己不会写,是借助scipy.cluster下的hierarchy实现的...直接写在了main()函数里。
main()函数
def main():
filepath = 'D:/Desktop/testdata.xlsx'
df = pd.read_excel(filepath)
df_std = z_score_std(df)
print("原始数据为:")
print(df)
print("Z-Score标准化后的数据为:")
print(df_std)
row = np.size(df_std, 0)
matrix_d = get_d_mat(row, df_std)
fuzzy_sim_matrix = get_fuz_sim_mat(matrix_d, row)
fuzzy_eql_matrix = get_fuz_eql_mat(fuzzy_sim_matrix, row)
count = 0
res_mat = final_fuz_eql_mat(fuzzy_eql_matrix, row, count)
print("模糊等价矩阵为:")
print(res_mat)
print("树谱图为:")
Z = hierarchy.linkage(res_mat, method ='average', metric='euclidean')
hierarchy.dendrogram(Z, orientation='right', labels = df.index+1) # index从0开始
plt.ylabel('sample')
plt.show()
thresh = float(input("请输入截取模糊等价矩阵的值(0-1范围内):"))
if thresh<0 or thresh>1 or type(thresh)!= float:
raise Exception("请检查输入的是否为数字或输入值的范围!")
res = cut_mat(res_mat, thresh)
clnum = get_classify_num(res)
print(f"当值为 {thresh} 时,截矩阵结果为:")
print(res)
print(f"共分 {clnum} 类。")
if __name__ == "__main__":
main()
2024年10月4日 21:02
看的我热血沸腾啊https://www.ea55.com/