3、K均值(K-means)算法——非监督、聚类
1、K均值(K-means)算法
K均值算法,是一种广泛使用的非监督聚类算法。该算法通过比较样本之间的相似性,将较为相似的样本划分到同一个类别中。由于K均值算法简单、易于实现的特点而得到广泛应用。
K均值算法的缺点: K值是用户给定的,在进行数据处理前,K值未知,不同的K值得到的结果也不一样;对初始簇中心敏感;不适合发现非凸形状的簇或者大小差别较大的簇;特殊值对模型的影响比较大。
K均值算法的优点: 容易理解,聚类效果不错;处理大数据集的时候,该算法可以保证较好的伸缩性;当簇近似高斯分布的时候,效果非常不错。
2、相似性度量
在K均值算法中,通过某种相似性度量的方法,将较为相似的个体划分到同一个类别中。对于不同的应用场景,有着不同的相似性度量的方法。为了度量样本X和样本Y之间的相似性,一般定义一个距离函数$d\left( {X,Y} \right)$来表示。
假设有两个点,分别为点P和点Q,其对应的坐标分别为:
$P = \left( {{x_1}{\rm{,}}{x_2}{\rm{,}} \cdots {\rm{,}}{x_n}} \right) \in {R^n}$
$Q = \left( {{y_1}{\rm{,}}{y_2}{\rm{,}} \cdots {\rm{,}}{y_n}} \right) \in {R^n}$
通常使用的距离函数有:
(1)闵可夫斯基距离
点P和点Q之间的闵可夫斯基距离可以定义为:
$d\left( {P{\rm{,}}Q} \right) = {\left( {\sum\limits_{i = 1}^n {{{\left( {{x_i} - {y_i}} \right)}^p}} } \right)^{\frac{1}{p}}}$
(2)曼哈顿距离
点P和点Q之间的曼哈顿距离可以定义为:
$d\left( {P{\rm{,}}Q} \right) = \sum\limits_{i = 1}^n {\left| {{x_i} - {y_i}} \right|} $
(3)欧式距离
点P和点Q之间的曼哈顿距离可以定义为:
$ d\left( {P{\rm{,}}Q} \right) = \sqrt {\sum\limits_{i = 1}^n {{{\left( {{x_i} - {y_i}} \right)}^2}} } $
在K均值算法中,选用欧式距离作为相似度的度量。
3、K均值算法原理
对于K均值算法,假设有m个样本$\left\{ {{X^{\left( 1 \right)}}{\rm{,}}{X^{\left( 2 \right)}}{\rm{,}} \cdots {\rm{,}}{X^{\left( m \right)}}} \right\}$,其中随机初始化k个聚类中心,通过每个样本与k个聚类中心之间的相似度,确定每个样本所属的类别,再通过每个类别中的样本重新计算每个类的聚类中心,重复这样的过程,直到聚类中心不再改变,最终确定每个样本所属的类别以及每个类的聚类中心。
K均值算法步骤:
- 初始化常数k,并随机初始化k个聚类中心;
- 重复计算以下过程,直到聚类中心不再改变;
- 计算每个样本与每个聚类中心之间的相似度,将样本划分到最相似的类别中;
- 计算划分到每个类别中的所有样本特征的均值,并将该均值作为每个类新的聚类中心。
- 输出最终的聚类中心以及每个样本所属的类别。
4、K均值算法Python实践
# coding:UTF-8 ''' Date:20160923 @author: zhaozhiyong ''' import numpy as np import matplotlib.pyplot as plt def load_data(file_path): '''导入数据 input: file_path(string):文件的存储位置 output: data(mat):数据 ''' f = open(file_path) data = [] for line in f.readlines(): row = [] # 记录每一行 lines = line.strip().split("\t") for x in lines: row.append(float(x)) # 将文本中的特征转换成浮点数 data.append(row) f.close() return np.mat(data) def distance(vecA, vecB): '''计算vecA与vecB之间的欧式距离的平方 input: vecA(mat)A点坐标 vecB(mat)B点坐标 output: dist[0, 0](float)A点与B点距离的平方 ''' dist = (vecA - vecB) * (vecA - vecB).T return dist[0, 0] def randCent(data, k): '''随机初始化聚类中心 input: data(mat):训练数据 k(int):类别个数 output: centroids(mat):聚类中心 ''' n = np.shape(data)[1] # 属性的个数 centroids = np.mat(np.zeros((k, n))) # 初始化k个聚类中心 for j in range(n): # 初始化聚类中心每一维的坐标 minJ = np.min(data[:, j]) rangeJ = np.max(data[:, j]) - minJ # 在最大值和最小值之间随机初始化 centroids[:, j] = minJ * np.mat(np.ones((k , 1))) \ + np.random.rand(k, 1) * rangeJ #计算公式:c = min + rand(0,1)*(max-min) return centroids def kmeans(data, k, centroids): '''根据KMeans算法求解聚类中心 input: data(mat):训练数据 k(int):类别个数 centroids(mat):随机初始化的聚类中心 output: centroids(mat):训练完成的聚类中心 subCenter(mat):每一个样本所属的类别(二维:类别、最小距离) ''' m, n = np.shape(data) # m:样本的个数,n:特征的维度 subCenter = np.mat(np.zeros((m, 2))) # 初始化每一个样本所属的类别 change = True # 判断是否需要重新计算聚类中心 while change == True: change = False # 重置 for i in range(m): minDist = np.inf # 设置样本与聚类中心之间的最小的距离,初始值为正无穷 minIndex = 0 # 所属的类别 for j in range(k): # 计算i和每个聚类中心之间的距离 dist = distance(data[i, ], centroids[j, ]) if dist < minDist: minDist = dist minIndex = j # 停止条件,判断是否需要改变 if (subCenter[i, 0] != minIndex): # 需要改变 change = True subCenter[i, ] = np.mat([minIndex, minDist]) # 重新计算聚类中心 for j in range(k): sum_all = np.mat(np.zeros((1, n))) r = 0 # 每个类别中的样本的个数 for i in range(m): if subCenter[i, 0] == j: # 计算第j个类别 sum_all += data[i, ] r += 1 for z in range(n): try: centroids[j, z] = sum_all[0, z] / r except: print (" r is zero") return centroids, subCenter def save_result(file_name, source): '''保存source中的结果到file_name文件中 input: file_name(string):文件名 source(mat):需要保存的数据 output: ''' m, n = np.shape(source) f = open(file_name, "w") for i in range(m): tmp = [] for j in range(n): tmp.append(str(source[i, j])) f.write("\t".join(tmp) + "\n") f.close() #作图 def show(dataSet, k, Centroids, clusterAssment): numSamples, dim = dataSet.shape mark = ['or', 'ob', 'og', 'ok', '^r', '+r', 'sr', 'dr', '<r', 'pr'] #作样本点 for i in range(numSamples): markIndex = int(clusterAssment[i, 0]) plt.plot(dataSet[i, 0], dataSet[i, 1], mark[markIndex]) mark = ['Dr', 'Db', 'Dg', 'Dk', '^b', '+b', 'sb', 'db', '<b', 'pb'] #作聚类中心 for i in range(k): plt.plot(Centroids[i, 0], Centroids[i, 1], mark[i], markersize = 12) plt.show() if __name__ == "__main__": k = 4 # 聚类中心的个数 file_path = "data.txt" # 1、导入数据 print ("---------- 1.load data ------------") data = load_data(file_path) # 2、随机初始化k个聚类中心 print ("---------- 2.random center ------------") centroids = randCent(data, k) # 3、聚类计算 print ("---------- 3.kmeans ------------") myCentroids,subCenter = kmeans(data, k, centroids) # 4、保存所属的类别文件 print ("---------- 4.save subCenter ------------") save_result("sub", subCenter) # 5、保存聚类中心 print ("---------- 5.save centroids ------------") save_result("center", myCentroids) #作图 show(data, k, myCentroids,subCenter)
参考文献
[1] 赵志勇. Python机器学习算法[M]. 北京:电子工业出版社,2017.
[2] 李航. 统计学习方法[M]. 北京:清华大学出版社,2012.
[3] 周志华. 机器学习[M]. 北京:清华大学出版社,2016.
附录
数据集下载:
链接:https://pan.baidu.com/s/1X5-mITS7SCRHqmtpYYtRnA
提取码:wrqp