Kmeans原理实现——(python实现包含⼿肘法,kmeans++,
降维可视化)
⼀、总代码呈现
#n为样本数⽬
#m为特征数⽬
#k为簇⼼数⽬
#导⼊包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import copy as cp
from sklearn.decomposition import PCA
#计算欧⼏⾥得距离
def Eucl_distance(array_x,array_y):
return np.sum(np.square(shape(1,-1) - shape(1,-1)))
#⼿肘法
def elbow_k(data):#通过计算代价函数(或畸变函数)来确定K值
#吴达恩机器学习课上,k⼀般⼩于⼗类
k_cost=[]
for k in range(1,11):
final_center,belong=k_means(k)
cost=costfunc(final_center,data,k,belong)
k_cost.append(cost)
#x,y参数可以是标量,也可以是类似数组的数据结构(列表,numpy数组,pandas dataframe等)
plt.plot(np.array([i for i in range(1,11)]),np.array(k_cost),c='green')
#在点的最⼤值与最⼩值范围间随机给出随机簇⼼
def random_center(k):
initial_center=pd.s((k,m)))#注意对象类型,np.zeros是返回np.array类型⽽⾮pd.dataframe
min_columns=data.min(axis=0)#min(axis),max(axis)返回⼀个series对象
max_columns=data.max(axis=0)
random python
for i in range(k):#注意维度匹配的问题pd.dataframe
#np.random.函数
#np.array([]),⼩括号⾥的中括号起到了升维的作⽤
initial_center.iloc[i:i+1]=np.array([max_columns - np.random.random()*(max_columns - min_columns)])
#iloc主要⽤来取⾏
return initial_center
#代价函数
def costfunc(array_cent,data,k,book):#最终每⼀个簇⼼与每⼀个样本距离的和
Sum_cost=0
for i in range(k):
for j in range(n):#对每⼀个簇⼼的每⼀个样本
if i == book[j][0]:
Sum_cost+=Eucl_distance(array_cent[i:i+1],data.iloc[j:j+1].values)
return Sum_cost
def k_means(k):
initial_center=kpp_center(k)
final_s((k,m))
error=0.0001
distance=0
s((n,1))
s((n,1))
#确定每⼀个样本归属与哪⼀类
ifchange=True
while ifchange:
ifchange=False
tem_center=cp.deepcopy(initial_center)
for j in range(n):
min_dist=float('inf')
for i in range(k):
distance=Eucl_distance(initial_center.
iloc[i:i+1].values,data[j:j+1].values)
if distance < min_dist:
min_dist=distance
belong[j][0]=i
#重新分布簇⼼
for i in range(k):
Sum = 0
s((1,m))
for j in range(n):
if belong[j][0] == i:
Sum+=1
center+=data.iloc[j:j+1].values
if Sum != 0:
for h in range(m):
tem_center.iloc[i,h] = center[0][h]/Sum
else:
continue
#为簇⼼的移动设置误差
for i in range(k):
if Eucl_distance(tem_center.iloc[i:i+1].values,
initial_center.iloc[i:i+1].values) > error:
ifchange=True
initial_center.iloc[i:i+1] = tem_center.iloc[i:i+1]
for i in range(k):
final_center[i:i+1]=tem_center.iloc[i:i+1]
return final_center,belong
def kpp_center(k):
initial_center = pd.s((k,m)))
#确定第⼀个随机簇⼼
index = np.random.randint(1,n)
initial_center.iloc[0,:] = np.copy(data.iloc[index,:])
for i in range(k):
dist = []
for j in range(n):
#每⼀个样本与已知初始簇⼼们的最⼩距离
dist_temp=nearest_dist(data.iloc[j,:],initial_center.iloc[0:i,:])            dist.append(dist_temp)
Sum = sum(dist)
#确定基准概率
base_pro = np.random.random()
#将距离列表转换为概率列表
#将距离列表转换为概率列表
dist = [i/Sum for i in dist]
#法
for j ,value_j in enumerate(dist):
if base_pro < value_j:
initial_center.iloc[i,:] = np.copy(data.iloc[j,:])
break
else:
base_pro = base_pro - value_j
return initial_center
def nearest_dist(data_series,initial_center):
min_dist=float('inf')
lenth=initial_center.shape[0]
for i in range(lenth):
temp = Eucl_distance(np.array(data_series),initial_center.iloc[i,:].shape(1,-1))
if temp < min_dist:
min_dist = temp
return  min_dist
def PCA_datas(x):
dataMat = np.array(x)
pca_sk = PCA(n_components=2)
#利⽤PCA进⾏降维,数据存在newMat中
newMat = pca_sk.fit_transform(dataMat)
newMat = pd.DataFrame(newMat)
return newMat
def portion_visualize(k_final,final_data,final_center):
# ============================================================================= #    x_center=final_center[:,2]
#    y_center=final_center[:,1]
#    plt.scatter(x_center,y_center,c='red')
# =============================================================================
res=['green','blue','pink','yellow','black','violet']
for i in range(k_final):
xy_data = final_data[final_data[m] == i]
x_data = xy_data.iloc[:,1].shape(1,-1)
y_data = xy_data.iloc[:,1].shape(1,-1)
plt.scatter(x_data,y_data,c=res[i])
plt.show()
return 0
def visualize(k_final,final_data,final_center):
# ============================================================================= #    x_center=final_center.iloc[:,0]
#    y_center=final_center.iloc[:,1]
#    plt.scatter(x_center,y_center,c='red',marker = 'x')
# =============================================================================    res=['green','blue','pink','yellow','black','violet']
for i in range(k_final):
xy_data = final_data[final_data[2] == i]
x_data = xy_data.iloc[:,0].shape(1,-1)
y_data = xy_data.iloc[:,1].shape(1,-1)
plt.scatter(x_data,y_data,c=res[i])
plt.show()
return 0
#导⼊数据
#导⼊数据
ad_table("D:\date engineering\pythonstudy\",header=None,sep=',')
n=data.shape[0]
m=data.shape[1]
# =============================================================================
# elbow_k(data)#先运⾏这个确定k值
# =============================================================================
k_final=int(input('所以你选择多少为最终k值?'))
final_center,belong=k_means(k_final)
belong = pd.DataFrame(belong)
final_data = pd.concat([data,belong],axis=1,join='inner',ignore_index=True)
#选取两列数据进⾏画图呈现
portion_visualize(k_final,final_data,final_center)
data=PCA_datas(data)
final_center = PCA_datas(final_center)
belong = pd.DataFrame(belong)
data = pd.DataFrame(data)
final_data = pd.concat([data,belong],axis=1,join='inner',ignore_index=True)
#降维后实现可视化
visualize(k_final,final_data,final_center)
2.1 对kmeans算法的理解
(1)kmeans算法基本介绍:
kmeans算法是⽆监督学习中经典的分类算法,且仍具有相当多的优点。Kmeans算法的基本思想是:在空间样本点中选取k个簇⼼,对簇⼼周围的点进⾏归类,同时更新簇⼼⾄整个簇的中⼼。通过迭代,使簇⼼的位置收敛,呈现出最好的分类效果。
(2)kmeans算法优缺点:
优点:
①:原理简单,实现容易,收敛速度快
②:当结果簇是密集的,⽽簇与簇之间区别明显时,他的效果好
③:主要需要调节的参数仅仅时簇数k
缺点:
①:K值需要预先给定,很多情况下K值是很难估计的
②:对于初始选取的质⼼是敏感的,不同的初始簇⼼得到的聚类结果完全不同,对结果影响⼤
③:采⽤迭代的⽅法,可能只能得到局部的最优解,⽽⽆法得到全局的最优解
(3)kmeans算法步骤:
Ⅰ.在实验样本中选出k个初始簇⼼;
Ⅱ.将离簇⼼近的样本划分为同⼀类;
Ⅲ.由分类的结果对簇⼼进⾏重新分类;
Ⅳ若簇⼼尚未收敛,则重复Ⅱ、Ⅲ步骤;
Ⅴ对分好的簇进⾏可视化处理。
2.2 kmeans算法的实现步骤
Ⅰ.Kmeans算法需要⾸先获得⼀个初始簇⼼,这⾥实现分治化管理,创⽴了随机簇⼼函数。随机簇⼼的实现也很简单,我在样本中的每⼀维特征中的最⼩值与最⼤值之间随机选取了⼀个值,这⾥利⽤了min()与max(),random.random()函数,将他们组合k次成为初始簇⼼。在之后的kmeans优化中我会对
给出初始簇⼼的⽅法进⾏优化,也就是kmeans++算法
Ⅱ.在判断周围哪些点属于某⼀簇时,我们会计算距离,通过这个距离来衡量哪些簇⼼离某⼀样本点更近,这⾥通俗的距离衡量公式是欧式距离,也是空间点之间的距离
这⾥我并没有除以根号,因为在kmeans中只需⽐较距离之间的⼤⼩,且后⾯代价函数的计算中会运⽤到欧式距离的平⽅和。
Ⅲ在上⼀步骤中我们⽤到了kmeans算法,在这我们给予详细说明:
初始化变量
在这⾥对每⼀个样本,初始化最⼩距离为⽆穷⼤,然后得出该样本离哪个簇⼼最近,并记录该样本属于哪个簇⼼。最终得知⼀个簇中有哪些样本。
在这⼀步对簇⼼进⾏重新分布,并以簇内样本平均值的⽅式实现。也就是遍历每⼀个簇⼼下的每⼀个样本,判断其所属的类。这⾥格外的要注意,可能⼀个簇中⼀个样本点都没有,这可能会在分布簇⼼
时导致除零错误。因此对该情况进⾏了考虑,增强了程序的健状性。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。