目录
简介:
K-means聚类算法是一种无监督学习算法,主要用于将数据划分为K个预定义的簇或集群。这种算法的核心思想是通过迭代的方式,将数据点划分为K个集群,使得每个数据点与其所属集群的质心(即集群中所有点的平均值)的距离之和最小。
1 算法步骤:
核心:最小化所有样本到所属类别中心的欧式距离和
2 算法实战:
2.1 数据准备
数据来源:Iris - UCI 机器学习存储库
2.2 数据处理
将鸢尾花数据集的4个特征数据转化到【0,1】区间内。
2.3 Kmeans运行过程图展示
初始化k=3(聚类个数)
由上图可知每次迭代聚类中心得变化情况,并且该次运行是第4和5次的聚类中心没有发生改变故此停止迭代。
我们再将所有数据点离各自聚类中心的距离求和作为聚类的误差从而可计算出每次迭代的误差值故可绘制出历史迭代的误差变化图如下图所示。
3 总结:
3.1 kmeans算法的优缺点
优点:
-
简单易懂:K-Means算法的原理相对简单,易于理解和实现。它基于距离度量进行数据点的聚类,直观且易于解释。
-
高效性:在大数据集上,K-Means算法通常具有较快的收敛速度,能够高效地处理大规模数据。
-
可伸缩性:K-Means算法能够处理不同规模的数据集,从较小的数据集到非常大的数据集都能适用。
-
只依赖一个参数:算法主要依赖K值的选择,即需要划分的簇的数量。相对于其他聚类算法,K-Means的参数调整相对简单。
缺点:
-
K值选择困难:K值的选择对于聚类结果至关重要,但确定合适的K值并不容易。过小的K值可能导致信息丢失,过大的K值则可能使得聚类结果过于琐碎。
-
对初始值敏感:K-Means算法的初始簇中心是随机选择的,这可能导致算法陷入局部最优解,而非全局最优解。
-
对异常值敏感:算法对噪音和异常值比较敏感,因为这些点可能会显著影响簇中心的计算,导致聚类结果不准确。
-
不适合非凸形状的数据:K-Means算法基于距离度量进行聚类,因此对于形状复杂或非凸的数据集,可能难以得到理想的聚类结果。
3.2 kmeans 的运用场景
-
市场细分:在市场营销中,K-Means算法可以用于客户细分,将客户按照购买行为、兴趣偏好等特征进行聚类,从而制定更精准的营销策略。
-
图像分割:在图像处理领域,K-Means算法可以用于图像分割,将图像中的像素按照颜色、纹理等特征进行聚类,实现图像的自动分割和识别。
-
文本聚类:在文本处理中,K-Means算法可以用于文档的自动聚类,将相似的文档归类在一起,便于信息检索和主题分析。
-
基因表达数据分析:在生物信息学中,K-Means算法可以用于基因表达数据的聚类分析,帮助科学家发现基因之间的关联性和功能模式。
总之,K-Means算法在多个领域都有广泛的应用,尤其在需要基于特征相似性进行分组或分类的场景中表现出色。然而,在使用时需要注意其局限性,并根据实际情况进行参数调整和优化。
4 代码总汇:
from sklearn import preprocessing
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = "SimHei"#汉字乱码的解决方法
class kmeans:
def __init__(self,k):
self.k=k
def distance(self,point1,point2):
return np.sqrt(np.sum((point1 - point2) ** 2))
#类别的计算
def fit(self,x,centers):
#随机选取k个聚类中心
n,m=np.shape(x)
Dis=[]#存储个点到聚类中心的距离
cluster=[]#存储类别
#计算点到聚类中心的距离
for i in range (n):
dis=[]
for j in range(self.k):
L=self.distance(x[i,:],centers[j,:])
dis.append(L)
cluster.append(np.argmin(dis))
Dis.append(dis)
Dis=np.array(Dis)
return cluster
#更新聚类中心
def renewcenters(self,x,cluster):
n,m=np.shape(x)
renew = np.zeros((self.k, m))
renew=np.array(renew)
for i in range(self.k):
c=0#记录同类的个数
for j in range(n):
if cluster[j]==i:
renew[i,:]=renew[i,:]+x[j,:]
c=c+1;
renew[i,:]=renew[i,:]/c
return renew
#类别预测
def predict(self,x1,centers):
cids=[]
for i in range(self.k):
t=self.distance(x1,centers[i,:])
cids.append()
return np.argmin(cids)
#计算点到各自中心的距离的误差总计
def Errors(self,x,centers,cluster):
n,m=np.shape(x)
errors=0
for i in range(self.k):
for j in range(n):
if cluster[j]==i:
errors=errors+self.distance(centers[i,:],x[j,:])
return errors
#分类图绘制
def pictureshow(self,x,cluster,centers,_):
cluster=np.array(cluster)
x=np.array(x)
centers=np.array(centers)
colors = ['red', 'green', 'orange'] # 建立颜色列表
labels = ['Zero', 'One', 'two']
for i in range(k):
#将不同类的点找出来(cluster=i)并绘制图像
plt.scatter(x[cluster == i, 0], x[cluster == i, 1], c=colors[i], label=labels[i])
#绘制聚类中心
plt.scatter(centers[i,0],centers[i,1],c=colors[i],s=500,marker='*')
#注意为了使每个类别的散点图在同一副图上故要在for循环外
plt.title("第{}次迭代的分类图".format(_))
plt.xlabel("第一个特征向量")
plt.ylabel("第二个特征向量")
plt.show()
shuju2 = pd.read_excel(r'C://Users//86182//Desktop//iris.xlsx', sheet_name='Sheet1')
x=np.array(shuju2)[:,0:4]
min_max_scaler = preprocessing.MinMaxScaler()
x = min_max_scaler.fit_transform(x)
k=3
kmeans=kmeans(k)
iters=6
historyerrors=[]#存储不同聚类中心得聚类误差值
bestcenters=[]#记录最好的聚类中心
bestcluster=[]#记录最好的聚类分类
besterrors=10000
#聚类中心的初选
centers=x[np.random.choice(range(len(x)), k, replace=False)]
for _ in range (iters):
print("第{}次聚类中心:{}".format(_,centers))
#类别计算
cluster=kmeans.fit(x,centers)
#绘制散点图
kmeans.pictureshow(x,cluster,centers,_)
#误差计算
errors=kmeans.Errors(x,centers,cluster)
print("第{}次聚类的误差:{}".format(_, errors))
if errors<=besterrors:
bestcenters=centers.copy()
bestcluster=cluster.copy()
besterrors=errors.copy()
historyerrors.append(errors)
#更新聚类中心
centers1=kmeans.renewcenters(x,cluster)
#会出现反常情况比如误差增加了但下一次聚类中心也没改变就停止了故找到的并不是全局最优
if kmeans.distance(centers,centers1)==0:
print("迭代{}次提前结束".format(_))
break
else:
centers=centers1.copy()
print("全局最好的聚类中心:{}".format(bestcenters))
print("全局最好的聚类分类:{}".format(bestcluster))
print("全局最小的聚类误差:{}".format(besterrors))
#将最终的聚类效果存储在excle中
df = pd.DataFrame({'类别': cluster})
df.to_excel("C://Users//86182//Desktop//pythonsjdc.xlsx",sheet_name='sheet1', index=False)
#画出历史迭代的误差图
l=[i for i in range(len(historyerrors))]
plt.plot(l,historyerrors,color="g",marker="o")
plt.xlabel("迭代次数")
plt.ylabel("误差")
plt.show()