学习笔记:机器学习实战之Kmeans

kmeans算法注释版,新手小白,如有错误,还请不吝指教

#Kmeans算法
def kMeans(dataSet, k):
    dataSet = mat(dataSet)  #转换成mat类型
    m = shape(dataSet)[0]   #获取数据集的行数
    #第一列记录数据集的类别,第二列记录数据集到聚类中心的距离
    clusterAssment = mat(zeros((m,2)))#初始化
    centroids = randomCentroids(dataSet, k)#获取聚类中心
    clusterChanged = True   #用于判断聚类中心是否改变
    while clusterChanged:
        clusterChanged = False
        for i in range(m):
            minDist = inf   #最小距离初始化
            minIndex = -1   #最小距离下标初始化
            for j in range(k):
                #求解聚类中心与数据集的欧式距离
                distance = euclideanDistance(centroids[j,:],dataSet[i,:])
                if distance < minDist:
                    minDist = distance
                    minIndex = j
            if clusterAssment[i,:] != minIndex:
                clusterChanged = True
            clusterAssment[i,:] = minIndex,minDist**2
        print(centroids)#输出聚类中心
        for cent in range(k):
            ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]
            centroids[cent,:] = mean(ptsInClust, axis=0)#axis=0表示在列上对聚类中心的数据取平均值,即更新聚类中心

    return centroids, clusterAssment

对于下面这行代码,单独解释。

ptsInClust = dataSet[nonzero(clusterAssment[:,0].A==cent)[0]]

举个例子:

    a = [[0,1],[2,0],[3,0],[0,4]]
    a = mat(a)
    print(a)

输出为:

[[0 1]
 [2 0]
 [3 0]
 [0 4]]
此时a是一个4*2的矩阵,若使用nonzero()函数,则有输出
   print(nonzero(a))
(array([0, 1, 2, 3], dtype=int64), array([1, 0, 0, 1], dtype=int64))

可见,nonzero(),返回两个元组:

第一个元组里有,不为零元素的行的索引,以及该元素的类型

第二个元组中则是不为零元素的列的索引,以及该元素的类型

而对于Kmeans算法中的第25行代码中的.A,其实是就是返回数组本身。

在Kmeans这个代码里,矩阵类型和数组(array)类型的形式是一样的,所以加不加.A结果都一样。

具体参考numpy官方文档

https://docs.scipy.org/doc/numpy/reference/generated/numpy.matrix.A.html#numpy.matrix.A

贴个图,我想文档中的.A和Kmeans算法中的.A应该是一回事。


拿之前的矩阵a举例(下同):

    print(nonzero(a[:,0].A))
    print(nonzero(a[:,0]))
(array([1, 2], dtype=int64), array([0, 0], dtype=int64))
(array([1, 2], dtype=int64), array([0, 0], dtype=int64))

在Kmeans算法中,要在数据集中选择和聚类中心相同类别的下标,并且将该条数据归类到该聚类中心,

首先要得到该数据的下标,假设现在要求第三个聚类中心的下标,有如下代码:

    print(nonzero(a[:,0].A==3))
    print(nonzero(a[:,0]==3))
(array([2], dtype=int64), array([0], dtype=int64))
(array([2], dtype=int64), array([0], dtype=int64))

由上面的结果可知,返回了两个元组,但是我们只想得到该条数据的下标,所以只需取它的行信息,则有:

    print(nonzero(a[:,0].A==3)[0])
    print(nonzero(a[:,0]==3)[0])
[2]
[2]

发现输出为该条数据的下标,即我们想要的结果,同时我们也可以观察到,无论有没有.A,结果都是一样的。


解释完毕,实在是学不动了,写个博客放松一下心情。


参考资料:  https://blog.csdn.net/u013698770/article/details/54632047

猜你喜欢

转载自blog.csdn.net/folk_/article/details/80560333