今天在搞数模比赛时候研究了一下K-means均值算法,感觉这次写的还不错,发表成我的第一篇文章吧,我觉得发布文章也是一个好的总结,关于K-means算法的原理我就不过多赘述,站里有很多优秀的文章,这里主要介绍一下我实现的过程
库的引用
首先需要引用的库
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
import math
import numpy as np
import random
数据读取
然后从excel中读取数据,将读取的数据用列表存储
def Read_Dataset():
file_path = r'E:\pycharm\classify\Dataset.xlsx'
data = pd.read_excel(file_path, header=1)
dataset_frame = data.iloc[:,222:235]#用iloc读取文件
dataset = []
for i in range(len(dataset_frame.iloc[:,0])):#遍历列长
dataset.append(dataset_frame.iloc[i,:].tolist())#将每一行数据存入一个list,最终存入二维数组dataset
return dataset
算法部分
距离计算
计算每个点对于簇中心的距离,返回包含所有信息的列表
def Instance_Caculate(dataset,center_point_list):
characteristic_number = len(dataset[0])#数据特征数量
distance_list = []#最终返回的所有数据点与所有簇中心距离信息的列表
for i in range(len(dataset)):
one_point_distance_list = []#一个点和所有簇之间距离列表
for j in range(len(center_point_list)):
one_point_for_one_center_distance_list =[]
for k in range(characteristic_number):
one_feature_distance = dataset[i][k] - center_point_list[j][k]
one_point_for_one_center_distance_list.append(one_feature_distance**2)
one_point_distance_list.append(math.sqrt(sum(one_point_for_one_center_distance_list)))
distance_list.append(one_point_distance_list)
return distance_list
分类
接下来是用于分类的函数,把每个点进行分类
def Classify(distance_list):
classify_result_list = []
ori_list = distance_list
sorted_list = []#排序后的距离列表,目的是找出一个点距离其最近的簇中心
for i in range(len(distance_list)):
sorted_data = sorted(distance_list[i])
sorted_list.append(sorted_data)
for i in range(len(ori_list)):
classify_result = ori_list[i].index(sorted_list[i][0])
classify_result_list.append(classify_result)#所有数据点分类结果列表
return classify_result_list
更新中心点
根据分类结果更新新的类型中心点
def Update(dataset,classify_result_list,last_center):#迭代函数,输入数据集,分类结果集,以及迭代的中心点
characteristic_number = len(dataset[0])
center_num = len(last_center)
cnt_sum = [0]*k#建立一个存储每一个分类的种群数量信息的集合
update_center_sum = [[0]*characteristic_number for i in range(center_num)]
update_center = [[0]*characteristic_number for i in range(center_num)]#最终更新中心点结果
for i in range(len(classify_result_list)):
for j in range(characteristic_number):
update_center_sum[classify_result_list[i]][j] += dataset[i][j]#计算出每个类别的数据和
cnt_sum[classify_result_list[i]] += 1
for i in range(len(update_center_sum)):
for j in range(characteristic_number):
update_center[i][j] = update_center_sum[i][j]/cnt_sum[i]
change = []#每次迭代的改变量,作为迭代结束的标志
for i in range(center_num):
update_distance_list = []
for j in range(characteristic_number):
one_feature_distance = last_center[i][j] - update_center[i][j]
update_distance_list.append(one_feature_distance**2)
change.append(math.sqrt(sum(update_distance_list)))
return change,update_center
迭代
这些准备好之后,放入迭代函数
def interation(dataset,center):#输入数据集和中心点初值
change = [10]#每一次迭代的改变值,赋了一个不为零的值作为初值
change_list = []#每次迭代变化值计数
update_center = []#迭代中心点列表
classify_result_list = []
cnt = 0#迭代次数计数
while (sum(change) != 0):#当中心点位置不在改变停止迭代
if (cnt == 0):
distance_list = Instance_Caculate(dataset, center)
classify_result_list = Classify(distance_list)
change, update_center = Update(dataset, classify_result_list, center)
else:
distance_list = Instance_Caculate(dataset, update_center)
classify_result_list = Classify(distance_list)
change, update_center = Update(dataset, classify_result_list, update_center)
change_list.append(change)
cnt += 1
print(change)
return change_list,classify_result_list,update_center,cnt#返回每次迭代改变值统计列表,新的分类结果列表,新的中心点,以及迭代次数
可视化部分
到这里算法部分的函数就结束了,接下来是可视化部分,这里我分为了两张图,一个是分类结果的散点图,另一个是迭代过程的折线图
我将最后得到的结果存储到一个三维列表中,第一维度就是每个点的不同特征,第二个维度是不同的点,第三个维度的索引就是分类类别,也就是类别0到类别n,为了后续显示出区别
def Result_Organizations(dataset,classify_result_list):
organizations = [[] for i in range(k)]
for i in range(len(dataset)):
organizations[classify_result_list[i]].append(dataset[i])
return organizations
汉字显示函数
def Chinese_Define ():
plt.rcParams['font.family'] = 'SimHei'
plt.rcParams['axes.unicode_minus']=False
随机颜色函数
def randomcolor():
colorArr = ['1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
color = ""
for i in range(6):
color += colorArr[random.randint(0,14)]
return "#"+color
分类结果可视化
结果的可视化,把数据先存入x,y集合中再显示会比整个数据集迭代显示运行起来快很多
def Result_Reveal(dataset,classify_result_list,organizations,update_center):#分类结果显示,输入数据集,分类集合(这两个可以不用,我是方便后续改)数据分类结果,以及最终中心点集
color_list = []#用于记录下分类的颜色,后续与迭代过程可视化颜色对齐
axe1 = plt.subplot(121)
for i in range(k):
x = []
y = []
for j in range(len(organizations[i])):
x.append(organizations[i][j][0])
y.append(organizations[i][j][1])
color = randomcolor()
axe1.scatter(x, y, marker='o', color=color, s=8)
color_list.append(color)
x = []
y = []
for i in range(len(update_center)):
x.append(update_center[i][0])
y.append(update_center[i][1])
axe1.scatter(x, y, marker='x', color='red', s=15)
return color_list
迭代过程可视化
接下来是迭代过程的显示
def Update_Feature_Reveal(change_list,cnt,color_list):#输入迭代中每轮改变值的统计列表,迭代次数,以及对应分类结果的颜色列表
change_list_reshape = [[] for i in range(len(change_list[0]))]
for i in range(len(change_list)):
for j in range(len(change_list[0])):
change_list_reshape[j].append(change_list[i][j])
ax2 = plt.subplot(122)
for i in range(len(change_list[0])):
ax2.plot(np.arange(1,cnt+1,1),change_list_reshape[i],c = color_list[i],
marker = 'D',label = f'中心{i}变化值')
ax2.legend()
把plt.show()打成了个函数
def Show():
plt.show()
PCA降维
多维数据下的降维处理,用到了pca函数直接处理
def Pca_Transform(organizations,update_center):
pca = PCA(n_components=2)
organizations_pca = [[] for i in range(k)]
update_center_pca = []
for i in range(k):
organizations_pca[i] = pca.fit_transform(organizations[i])
update_center_pca = pca.fit_transform(update_center)
return organizations_pca,update_center_pca
主函数
这里改变k值更改分类数量,我用的这个数据集有7000左右个数据
if __name__ =='__main__':
Chinese_Define()
dataset = Read_Pca_Transformed_Dataset()
k = 11
center =[]
for i in range(k):
index = random.randint(0,len(dataset))
center.append(dataset[index])
change_list,classify_result_list,update_center,cnt = interation(dataset,center)
organizations = Result_Organizations(dataset,classify_result_list)
organizations_pca, update_center_pca = Pca_Transform(organizations, update_center)#pca降维的数据接收
plt.figure()
color_list = Result_Reveal(dataset,classify_result_list,organizations,update_center)#这里如果是二维以上数据改为上两行的organizations_pca, update_center_pca
Update_Feature_Reveal(change_list,cnt,color_list)
Show()
运行结果展示
我发现多维数据分类后再降维显示会很乱,这里就以二维数据展示
完整代码
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
import math
import numpy as np
import random
def Chinese_Define ():
plt.rcParams['font.family'] = 'SimHei'
plt.rcParams['axes.unicode_minus']=False
def Read_Dataset():
file_path = r'E:\pycharm\classify\Dataset.xlsx'
data = pd.read_excel(file_path, header=1)
dataset_frame = data.iloc[:,222:235]#用iloc读取文件
dataset = []
for i in range(len(dataset_frame.iloc[:,0])):#遍历列长
dataset.append(dataset_frame.iloc[i,:].tolist())#将每一行数据存入一个list,最终存入二维数组dataset
return dataset
def Read_Pca_Transformed_Dataset():
file_path = 'E:\pycharm\pca_write\Dataset_pca_transformed.xlsx'
dataset_frame= pd.read_excel(file_path, header=0)
dataset = []
for i in range(len(dataset_frame.iloc[:, 0])):
dataset.append(dataset_frame.iloc[i, :].tolist())
return dataset
def randomcolor():
colorArr = ['1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
color = ""
for i in range(6):
color += colorArr[random.randint(0,14)]
return "#"+color
def Instance_Caculate(dataset,center_point_list):
characteristic_number = len(dataset[0])#数据特征数量
distance_list = []#最终返回的所有数据点与所有簇中心距离信息的列表
for i in range(len(dataset)):
one_point_distance_list = []#一个点和所有簇之间距离列表
for j in range(len(center_point_list)):
one_point_for_one_center_distance_list =[]
for k in range(characteristic_number):
one_feature_distance = dataset[i][k] - center_point_list[j][k]
one_point_for_one_center_distance_list.append(one_feature_distance**2)
one_point_distance_list.append(math.sqrt(sum(one_point_for_one_center_distance_list)))
distance_list.append(one_point_distance_list)
return distance_list
def Classify(distance_list):
classify_result_list = []
ori_list = distance_list
sorted_list = []#排序后的距离列表,目的是找出一个点距离其最近的簇中心
for i in range(len(distance_list)):
sorted_data = sorted(distance_list[i])
sorted_list.append(sorted_data)
for i in range(len(ori_list)):
classify_result = ori_list[i].index(sorted_list[i][0])
classify_result_list.append(classify_result)#所有数据点分类结果列表
return classify_result_list
def Update(dataset,classify_result_list,last_center):#迭代函数,输入数据集,分类结果集,以及迭代的中心点
characteristic_number = len(dataset[0])
center_num = len(last_center)
cnt_sum = [0]*k#建立一个存储每一个分类的种群数量信息的集合
update_center_sum = [[0]*characteristic_number for i in range(center_num)]
update_center = [[0]*characteristic_number for i in range(center_num)]#最终更新中心点结果
for i in range(len(classify_result_list)):
for j in range(characteristic_number):
update_center_sum[classify_result_list[i]][j] += dataset[i][j]#计算出每个类别的数据和
cnt_sum[classify_result_list[i]] += 1
for i in range(len(update_center_sum)):
for j in range(characteristic_number):
update_center[i][j] = update_center_sum[i][j]/cnt_sum[i]
change = []#每次迭代的改变量,作为迭代结束的标志
for i in range(center_num):
update_distance_list = []
for j in range(characteristic_number):
one_feature_distance = last_center[i][j] - update_center[i][j]
update_distance_list.append(one_feature_distance**2)
change.append(math.sqrt(sum(update_distance_list)))
return change,update_center
def interation(dataset,center):#输入数据集和中心点初值
change = [10]#每一次迭代的改变值,赋了一个不为零的值作为初值
change_list = []#每次迭代变化值计数
update_center = []#迭代中心点列表
classify_result_list = []
cnt = 0#迭代次数计数
while (sum(change) != 0):#当中心点位置不在改变停止迭代
if (cnt == 0):
distance_list = Instance_Caculate(dataset, center)
classify_result_list = Classify(distance_list)
change, update_center = Update(dataset, classify_result_list, center)
else:
distance_list = Instance_Caculate(dataset, update_center)
classify_result_list = Classify(distance_list)
change, update_center = Update(dataset, classify_result_list, update_center)
change_list.append(change)
cnt += 1
print(change)
return change_list,classify_result_list,update_center,cnt#返回每次迭代改变值统计列表,新的分类结果列表,新的中心点,以及迭代次数
def Show():
plt.show()
def Result_Reveal(dataset,classify_result_list,organizations,update_center):#分类结果显示,输入数据集,分类集合(这两个可以不用,我是方便后续改)数据分类结果,以及最终中心点集
color_list = []#用于记录下分类的颜色,后续与迭代过程可视化颜色对齐
axe1 = plt.subplot(121)
for i in range(k):
x = []
y = []
for j in range(len(organizations[i])):
x.append(organizations[i][j][0])
y.append(organizations[i][j][1])
color = randomcolor()
axe1.scatter(x, y, marker='o', color=color, s=8)
color_list.append(color)
x = []
y = []
for i in range(len(update_center)):
x.append(update_center[i][0])
y.append(update_center[i][1])
axe1.scatter(x, y, marker='x', color='red', s=15)
return color_list
def Update_Feature_Reveal(change_list,cnt,color_list):#输入迭代中每轮改变值的统计列表,迭代次数,以及对应分类结果的颜色列表
change_list_reshape = [[] for i in range(len(change_list[0]))]
for i in range(len(change_list)):
for j in range(len(change_list[0])):
change_list_reshape[j].append(change_list[i][j])
ax2 = plt.subplot(122)
for i in range(len(change_list[0])):
ax2.plot(np.arange(1,cnt+1,1),change_list_reshape[i],c = color_list[i],
marker = 'D',label = f'中心{i}变化值')
ax2.legend()
def Result_Organizations(dataset,classify_result_list):
organizations = [[] for i in range(k)]
for i in range(len(dataset)):
organizations[classify_result_list[i]].append(dataset[i])
return organizations
def Pca_Transform(organizations,update_center):
pca = PCA(n_components=2)
organizations_pca = [[] for i in range(k)]
update_center_pca = []
for i in range(k):
organizations_pca[i] = pca.fit_transform(organizations[i])
update_center_pca = pca.fit_transform(update_center)
return organizations_pca,update_center_pca
if __name__ =='__main__':
Chinese_Define()
dataset = Read_Pca_Transformed_Dataset()
k = 11
center =[]
for i in range(k):
index = random.randint(0,len(dataset))
center.append(dataset[index])
change_list,classify_result_list,update_center,cnt = interation(dataset,center)
organizations = Result_Organizations(dataset,classify_result_list)
organizations_pca, update_center_pca = Pca_Transform(organizations, update_center)#pca降维的数据接收
plt.figure()
color_list = Result_Reveal(dataset,classify_result_list,organizations,update_center)#这里如果是二维以上数据改为上两行的organizations_pca, update_center_pca
Update_Feature_Reveal(change_list,cnt,color_list)
Show()