聚类算法 - KMeans - 机器学习实战

直接上代码:https://github.com/yjfiejd/k-means_3
# -*- coding:utf8 -*-
# @TIME : 2018/4/12 下午05:33
# @Author : yjfiejd
# @File : K-means_3.py

from numpy import *
import time
import matplotlib.pyplot as plt

# 1)先定义3个函数,第一个函数为导入数据函数
def loadDataSet(filename):
    dataSet = [] #定义一个数组用来存储导入的数据
    fr = open(filename) #打开文件
    for line in fr.readlines(): #便利文件的每一行,返回List
        curline = line.strip().split('\t') #对每一行格式化
        fltLine = map(float, curLine) #把每一行转为float类型
        datMat.append(fltLine) #使用append,把转换好对行,添加进dataSet数组

# 2)定义第二个函数,计算欧氏距离函数, 两个矩阵之间对距离,所以有sum
def distEclud(vector1, vector2):
    return sqrt(sum(power(vector2 - vector1, 2)))


# 3)定义随机对簇点,簇点来自与dataSet,注意随机簇点对对取值范围
def randCent(dataSet, k):
    n = shape(dataSet)[1] #获取矩阵列数,shape[行,列]
    centroids = mat(zeros((k, n))) #初始化簇矩阵,有K个质心, array转换为matrix格式
    for j in range(n): #遍历每一个列(特征—)
        minJ = min(dataSet[:, j]) #取每列中最小值
        maxJ = max(dataSet[:, j]) #取每一列中最大值
        rangeJ = float(maxJ - minJ) #计算簇对取值范围
        centroids[:, j] = mat(minJ + rangeJ*random.rand(k, 1)) #rand随机生成K行1列数组,其中值【0,1】
    return centroids

# 这个函数对另一种做法
#def initCentroids(dataSet, k):
#    numSamples, dim = dataSet.shape   #矩阵的行数、列数
#    centroids = zeros((k, dim))
#   for i in range(k):  #直接初始化簇点
#        index = int(random.uniform(0, numSamples))  #随机产生一个浮点数,然后将其转化为int型
#        centroids[i, :] = dataSet[index, :]
#    return centroids

# 4)定义Kmeans函数
def kMeans(dataSet, k):
    # 1)初始化存储点簇分配结果矩阵
    m = shape(dataSet)[0] #获取数据对行数,也就是样本点对个数
    clusterAssment = mat(zeros((m, 2))) #初始化簇对分类结果矩阵,m行,2列特征
    # 2) 初始化随机簇点
    centroids = randCent(dataSet, k) #初始化随机簇点
    clusterChange = True #定义循环判定条件,当簇点中心位置不再变化时,退出
    while clusterChange:
        clusterChange = False
        for i in range(m): #对每个样本计算最近对中心
            minDist = 1000000.0; #初始化minDist,第一次设置为很大对值
            minIndex = 0 #初始化索引,对应为,分到哪个簇
            for j in range(k): #对每个簇中心遍历,因为有多个,计算每个点到簇中心距离,把最小对进行归类
                distJI = distEclud(centroids[j, :], dataSet[i, :]) #计算距离
                if distJI < minDist:
                    minDist = distJI; #把小对值给minDist
                    minIndex = j #得到最近对中心,以及对应对j,簇号
                # 3) 更新cluster, 若所有对簇质心位置不变,则退出while循环
                # K个簇里第i个样本距离最小对标号和距离保存在clusterAssment
                if clusterAssment[i, :] != minIndex:
                    clusterChange = False
                    clusterAssement[i,:] = minIndex, minDist**2 #两个**表示对数minDist对平方
        #4)更新centroids,遍历簇心位置
        for j in range(k):
            #clusterAssment[:,0].A==j是找出矩阵clusterAssment中第一列元素中等于j的行的下标,返回的是一个以array的列表,第一个array为等于j的下标
            pointsInCluster = dataSet[nonzero(clusterAssment[:, 0].A == j)[0]]
            centroids[j, :] = mean(pointsInCluster, axis = 0)  #计算标注为j的所有样本的平均值

    print('finish')
    return centroids, clusterAssment

# 5)展示2D
def showCluster(dataSet, k , centroids, clusterAssment):
    m = shape(dataSet)[0] #行数
    n = shape(dataSet)[1] #列数
    if n != 2:
        print("sorry, can't draw because your data dimension is 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(m):
        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, i], mark[i], markersize = 12)

    plt.show()



## step 1: load data
import os
print ("step 1: load data..." )
dataSet = []   #列表,用来表示,列表中的每个元素也是一个二维的列表;这个二维列表就是一个样本,样本中包含有我们的属性值和类别号。
#与我们所熟悉的矩阵类似,最终我们将获得N*2的矩阵,
f = "/Users/a1/Desktop/算法实战/K-means/K-means_3/testSet.txt"
fileIn = open(f)  #是正斜杠
for line in fileIn.readlines():
    temp=[]
    lineArr = line.strip().split('\t')  #line.strip()把末尾的'\n'去掉
    temp.append(float(lineArr[0]))
    temp.append(float(lineArr[1]))
    dataSet.append(temp)
    #dataSet.append([float(lineArr[0]), float(lineArr[1])])#上面的三条语句可以有这条语句代替
fileIn.close()
## step 2: clustering...
print ("step 2: clustering..."  )
dataSet = mat(dataSet)  #mat()函数是Numpy中的库函数,将数组转化为矩阵
k = 4
centroids, clusterAssment = kMeans(dataSet, k)  #调用KMeans文件中定义的kmeans方法。

## step 3: show the result
print ("step 3: show the result..."  )
KMeans.showCluster(dataSet, k, centroids, clusterAssment)

猜你喜欢

转载自blog.csdn.net/sinat_15355869/article/details/79922659