机器学习之聚类算法k-means

一、目的意义

内容包括:

1)问题描述:k-means聚类算法的研究,此算法主要对二维数据点进行聚类。

二、算法阐述(占20%

---输入:期望得到的簇的数目kn个对象的二维数据D

---输出:k个簇的集合。

算法步骤:

1)输入kn个二维数据对象

     2)随机选择k个对象作为初始的簇的质心

3repeat

4)计算每个对象与各个簇的质心的距离,将对象划分到距离     其最近的簇

5)重新计算每个簇的质心并更新

6until所有分类下标都等于最小下标,算法停止

7)输出这k个簇的集合。

三、算法实现(占30%

 []:以下代码为算法的主要代码

命名为k_means.py的文件,此文件下的代码为:

from numpy import *
import matplotlib.pyplot as plt



#计算欧氏距离
def euclDistance(vector1, vector2):
   return sqrt(sum(power(vector2 - vector1, 2)))
    
#初始化质心,采用随机产生质心
def initCentroids(dataSet, k):
    numSamples, dim = dataSet.shape
    #numSamples = 80
    #dim = 2
    
    centroids = mat(zeros((k, dim)))
    #[[ 0.  0.]
    # [ 0.  0.]
    # [ 0.  0.]
    # [ 0.  0.]]
    for i in range(k):
        index = int(random.uniform(0, numSamples)) #产生随机数,如果随机数产生相等了,如22,40,22,13,那么显示的聚类将减少,因为有个聚类的结果始终为空
        #print(index)
        centroids[i, :] = dataSet[index, :]
    #print(centroids)
    return centroids
#centroids
#[[-2.123337  2.943366]
# [ 2.046259  2.735279]
# [-2.967647  2.848696]
# [ 3.542056  2.778832]]    


#centroids, clusterAssment = k_means.kmeans(dataSet, k)    
#k-means
def kmeans(dataSet, k):
    numSamples = dataSet.shape[0]  #计算行数用0,计算列数用1, numSamples=80
    clusterAssment = mat(zeros((numSamples, 2))) #80*2的零矩阵
    clusterChanged = True
    centroids = initCentroids(dataSet, k) #初始化质心
    while clusterChanged:
        clusterChanged = False
        for i in range(numSamples):  #循环80行
            minDist = 100000.0  #假设当前的这个距离最小
            minIndex = 0
            
            for j in range(k): # 求出每一行距离最小的下标,最小下标即是每个点所属类别
                distance = euclDistance(centroids[j],dataSet[i])
                if distance < minDist:
                    minDist = distance
                    minIndex = j
            if clusterAssment[i, 0] != minIndex: #对象的下标不等于最小下标,直到所有对象下标都等于最小下标,算法停止。
                clusterChange = True
                clusterAssment[i, :] = minIndex, minDist**2
                #print(clusterAssment[i, :])
                #[[ 2.          2.32363089]]
                #[[ 1.          0.14270381]]
                #[[ 3.          9.63189586]]
    for j in range(k):  #将同一个簇的点放在一起
        pointsInCluster = dataSet[nonzero(clusterAssment[:, 0] == j)[0]]
        #print(pointsInCluster)
        #print(nonzero(clusterAssment[:, 0] == j))
        #(array([ 3, 27, 51, 71, 79]), array([0, 0, 0, 0, 0]))
        centroids[j, :] =mean(pointsInCluster, axis = 0) #计算每一列的均值,得出每个簇的质心
        #print(centroids) #[[ 1.09078155 -3.17263173]
                         # [ 2.6265299   3.10868015]
                         # [ 4.589752   -1.575316  ]
                         # [-3.03458403  0.53734279]]
    return centroids, clusterAssment


def showCluster(dataSet, k, centroids, clusterAssment):
    numSamples, dim = dataSet.shape
    if dim != 2:
        print("Sorry! I can not draw because the dimension of your data is not 2!")
        return 1
    #设定普通点颜色形状    
    mark = ['or','ob','og','ok','^r','+r','sr','dr','<r','pr']
    if k > len(mark):
        print("Sorry! Your k is too large!")
        return 1
     
    ## 画出所有样例点 属于同一分类的绘制同样的颜色   
    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()
        
     
        
    命名为test_kmeans.py的文件,此文件下的代码为:
import matplotlib
matplotlib.use('Tkagg')   #要想绘图成功,必须加上这两句,也可修改matplotlib的配置文件,
                          #则不用这两句
from numpy import *       #numpy 是python的函数库,
import matplotlib.pyplot as plt
import k_means
  
##处理数据,dataSet为嵌套列表[[1.658985, 4.285136], [-3.453687, 3.424321],.....]
print("loading data...")
dataSet = []  
fileIn = open('testSet.txt')  
for line in fileIn.readlines():
    
    lineArr = line.strip().split()
    #['1.658985', '4.285136']
    #['-3.453687', '3.424321']
    dataSet.append([float(lineArr[0]), float(lineArr[1])])
#dataSet   嵌套列表

print("clustering..."  )
dataSet = mat(dataSet)  ####转成80*2的矩阵

k = 4
centroids, clusterAssment = k_means.kmeans(dataSet, k)  

print("show the result...")
k_means.showCluster(dataSet, k, centroids, clusterAssment) 


测试数据文件,文件名为testSet.txt
1.658985    4.285136  
-3.453687   3.424321  
4.838138    -1.151539  
-5.379713   -3.362104  
0.972564    2.924086  
-3.567919   1.531611  
0.450614    -3.302219  
-3.487105   -1.724432  
2.668759    1.594842  
-3.156485   3.191137  
3.165506    -3.999838  
-2.786837   -3.099354  
4.208187    2.984927  
-2.123337   2.943366  
0.704199    -0.479481  
-0.392370   -3.963704  
2.831667    1.574018  
-0.790153   3.343144  
2.943496    -3.357075  
-3.195883   -2.283926  
2.336445    2.875106  
-1.786345   2.554248  
2.190101    -1.906020  
-3.403367   -2.778288  
1.778124    3.880832  
-1.688346   2.230267  
2.592976    -2.054368  
-4.007257   -3.207066  
2.257734    3.387564  
-2.679011   0.785119  
0.939512    -4.023563  
-3.674424   -2.261084  
2.046259    2.735279  
-3.189470   1.780269  
4.372646    -0.822248  
-2.579316   -3.497576  
1.889034    5.190400  
-0.798747   2.185588  
2.836520    -2.658556  
-3.837877   -3.253815  
2.096701    3.886007  
-2.709034   2.923887  
3.367037    -3.184789  
-2.121479   -4.232586  
2.329546    3.179764  
-3.284816   3.273099  
3.091414    -3.815232  
-3.762093   -2.432191  
3.542056    2.778832  
-1.736822   4.241041  
2.127073    -2.983680  
-4.323818   -3.938116  
3.792121    5.135768  
-4.786473   3.358547  
2.624081    -3.260715  
-4.009299   -2.978115  
2.493525    1.963710  
-2.513661   2.642162  
1.864375    -3.176309  
-3.171184   -3.572452  
2.894220    2.489128  
-2.562539   2.884438  
3.491078    -3.947487  
-2.565729   -2.012114  
3.332948    3.983102  
-1.616805   3.573188  
2.280615    -2.559444  
-2.651229   -3.103198  
2.321395    3.154987  
-1.685703   2.939697  
3.031012    -3.620252  
-4.599622   -2.185829  
4.196223    1.126677  
-2.133863   3.093686  
4.668892    -2.562705  
-2.793241   -2.149706  
2.884105    3.043438  
-2.967647   2.848696  
4.479332    -1.764772  
-4.905566   -2.911070

四、结果分析(占30%


图片解释:算法输出了四个簇,此次聚类结果比较不错,四个较大的点为质心,

图片解释:此次聚类算法明显不如人意,这也是此算法的缺点,易达到局部最优。


图片解释;我们希望的算法聚类个数是4,这里只有3个聚类,出现这也的原因是:簇的四个初始质心是随机选取的,有可能随机到同一个数,如(22,13,33,22),这样导致有一个簇始终为空,不过出现这种情况的概率还是很小的,这也是此算法最糟糕的结果。


 

 

 

五、总结(占15%

我们知道,任何算法都有它自身的优点与缺点,通过很多次的实验结果验证,我更加深刻理解了k-means的优点与缺点。

优点:k-means算法是聚类问题的经典算法,该算法简单快速。对于大数据量的数据,有相对较高的算法效率,它的伸缩性很高,常常以局部最优来结束算法。当簇是密集的,圆形的,团状的,而且簇与簇之前的区别明显时,它的聚类效果较好。

缺点:要求用户必须事先给出要生成的簇的数目k,这就好比世上先有鸡还是先有蛋的问题,这也是此算法无法避免的缺点。次算法对于初始值很敏感,对于不同的初始值,聚类的结果往往不同。对于噪声数据和孤立点数据非常敏感,少量的该数据能够对平均值产生巨大的影响。

这个算法也即将应用到一个平台上,对于这个算法的透侧研究,也将有助于我开发此软件,我知道,通过此次算法的研究,我已经学到了很多有用的东西。

猜你喜欢

转载自blog.csdn.net/wangyuanshun/article/details/72854252