本章介绍
本章将介绍如何利用K-均值算法进行聚类。在进行聚类之后,分析如何通过后处理手段来提高聚类性能。探讨二分K-均值是如何克服局部最小值问题。最后将使用地理坐标在地图上进行聚类。
K-均值算法
在讲K-均值算法前,我们需要对无监督学习的概念有所了解。无监督学习的特点是训练样本点标记信息未知,目标是通过对无标记样本数据的学习,解释数据的内在性质与规律。聚类是无监督学习算法中的一大分支。聚类将数据集中的样本划分为若干个子集(通常不想交),每个子集称为一个簇。簇的中心被称为质心。
K-均值算法则是一个经典的聚类算法,它对未标注的数据进行聚类,并生成K个类别(簇心)的算法。
K-均值的伪码表示如下:
创建k个点作为起始的质心(通常是随机选择)
当任意一个点的簇分配结果发生改变的时候:
对数据集中的每个数据点
对每个质心
计算很质心到数据点之间的距离
将数据点分配到距离其最近的簇
对每个簇,计算簇中所有点的均值并将均值作为质心
下面来看一下具体的实现
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
def loadDataSet(fileName):
'''
函数功能:
从文本中读取数据,并返回处理好的数据
参数:
fileName__文件名
返回值:
数据矩阵
'''
#创建一个列表存储从文件读取的数据
dataMat = []
#打开文件
fr = open(fileName)
#对文件的数据进行行遍历
for line in fr.readlines():
#由于一行有多个数据,所以要创建一个temp保存
temp = []
#将这一行数据按\t切分
curLine = line.strip().split('\t')
#fltLine = map(float, curLine)这行代码会导致数据类型变为map object,影响可视化,所以对代码进行改写
#得到当前行数据的数量
lenOfcurLine = len(curLine)
#遍历当前行所有数据
for i in range(lenOfcurLine):
#将数据转为float型存入temp
temp.append(float(curLine[i]))
#将temp放进dataMat里
dataMat.append(temp)
#返回从文件中读取到的并处理好的数据
return np.mat(dataMat)
def randCent(dataSet,k):
'''
函数功能:
根据数据的规模与K值随机生成中心点
参数:
dataSet__数据集
k__随机生成中心点的数量
返回值:
k个中心点组成的矩阵
'''
#shape是指数据的维度(m,n).m指数据集的数量,n指数据集的维度.
n = np.shape(dataSet)[1]
#生成一个维度为(k,n)的零矩阵
centroids = np.mat(np.zeros((k,n)))
#对所有列进行遍历
for j in range(n):
#找出第n列中最小值
minJ = np.min(dataSet[:,j])
#一列中最大值减去一列中最小值得到一个区间
rangeJ = float(np.max(dataSet[:,j]) - minJ)
#最小值+区间×随机系数.这样生成的中心点在整个数据集的边界之内
centroids[:,j] = minJ + rangeJ * np.random.rand(k,1)
#返回随机生成的中心点
return centroids
def distEclud(vecA ,vecB):
'''
函数功能:
计算两个点之间的欧氏距离
参数:
vecA__A点的坐标
VecB__B点的坐标
返回值:
两点之间的欧氏距离
'''
return np.sqrt(np.sum(np.power(vecA - vecB,2)))
def KMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
'''
函数功能:
对数据集进行K-均值聚类
参数:
dataSet__结构化、数值型的数据集
k__中心点个数
返回值:
聚类中心矩阵、聚类结果
'''
#数据集的行数
m = np.shape(dataSet)[0]
#数据集的列数
n = np.shape(dataSet)[1]
#创建一个大小为(m,2)的零矩阵,第0列是聚类的结果,第1列是该点到簇中心的距离
clusterAssment = np.mat(np.zeros((m,2)))
#利用函数createCent随机生成中心点完成初始化
centroids = createCent(dataSet, k)
#标记
clusterChanged = True
#如果所有在一轮聚类之后,所有点的分配都不发生改变,为False,结束聚类,否则为True,继续进行聚类
while clusterChanged:
#假定所有点分配都不发生改变,标记为False
clusterChanged = False
#遍历整个样本
for i in range(m):
#无穷大,用来记录点到簇的最小距离
minDist = np.inf
#默认值-1
minIndex = -1
#遍历所有的簇心
for j in range(k):
#计算每个样本与每个簇的距离
distJI = distMeas(centroids[j,:] ,dataSet[i,: