K-means算法中K指分成多少类,为数据挖掘十大算法之一。
- 基本原理:在非监督学习(Unsupervised Learning)中,没有标签用来分类,此时应如何分类?
K-means算法是一种解决方案,此实例较为简单,提前声明数据集要分类的数目,即K值。以空间中K个点为中心进行聚类,对最靠近他们的对象归类,逐次更新各聚类中心的值,直到最后的聚类结果。
- 算法描述:
-
- 适当选择k个类的初始中心,记为 c
- 在第k次迭代中,对任意一个样本,计算到c中各个中心点的距离,将该样本归到距离最短的中心x所在的类。即 data[i,-1]=x
- 利用均值等方法更新该类的中心值
- 对于所有的聚类中心,进行2、3迭代更新后,若c值保持不变,则迭代结束
- 示例:分类四个药物,特征值简单,只有2个
Object | Feature 1:Weight Index | Feature 2: pH |
---|---|---|
Medicine A | 1 | 1 |
Medicine B | 2 | 1 |
Medicine C | 4 | 3 |
Medicine D | 5 | 4 |
#!/usr/bin/env python
#coding:utf-8
#Author:Fabian
import numpy as np
def Kmeans(X, k, maxIt):
"""
kmeans聚类算法
:param X: 数据集
:param k: 分多少类
:param maxIt: 最大迭代次数
:return:
"""
numPoints, numDim = X.shape
print numPoints,numDim
#加一列
dataSet = np.zeros((numPoints, numDim + 1))
dataSet[:, :-1] = X
#Initialize centroids randomly
centroids = dataSet[np.random.randint(numPoints, size=k),:]
#centroids = dataSet[0:2, :]
#Randomly assign labels to initial centroid
centroids[:,-1] = range(1, k+1)
#Initialize book keeping vars
iterations = 0
oldCentroids = None
#Run the main k-means algorithm
while not shouldStop(oldCentroids, centroids, iterations, maxIt):
print "iteration: \n", iterations
print "dataSet: \n", dataSet
print "centroids: \n", centroids
#Save old centroids for convergence test.
oldCentroids = np.copy(centroids)
iterations += 1
#assign labels to each datapoint based on centroids
updateLabels(dataSet, centroids)
#assign centroids based on datapoint labels
centroids = getCentroids(dataSet, k)
return dataSet
def shouldStop(oldCentroids, centroids, iterations, maxIt):
"""
判断是否停止更新,超过返回True,否则判断是否相等,相等返回True
:param oldCentroids:上一次循环的中心点
:param centroids: 本次的中心点
:param iterations: 迭代次数
:param maxIt: 最大迭代数
:return: True or False
"""
if iterations > maxIt:
return True
return np.array_equal(oldCentroids, centroids)
def updateLabels(dataSet, centroids):
#For each element in the dataset, chose the closest centroid
"""
数据集中每个数据与中心点比较 选择最近的聚类
:param dataSet: 数据集
:param centroids: 中心
:return: No return
"""
numPoints, numDim = dataSet.shape
for i in range(0,numPoints):
dataSet[i, -1] = getLabelFromClosestCentroid(dataSet[i, :-1], centroids)
def getLabelFromClosestCentroid(dataSetRow, centroids):
#初始化label为中心点第一点的label
label = centroids[0, -1]
#初始化最小值为当前行到中心点第一点的距离值
#np.linalg.norm计算两个向量的距离
minDist = np.linalg.norm(dataSetRow - centroids[0, : -1])
#对每个中心点开始循环
for i in range(0, centroids.shape[0]):
dist = np.linalg.norm(dataSetRow - centroids[i, : -1])
if dist < minDist:
minDist = dist
label = centroids[i, -1]
print "minDist:",minDist
return label
def getCentroids(dataSet, k):
"""
更新中心点
:param dataSet: 数据集 + 标签
:param k: 分类数
:return: centroids
"""
result = np.zeros((k, dataSet.shape[1]))
for i in range(1, k+1):
#找出最后一列类别都为i的行集
oneCluster = dataSet[dataSet[:,-1] == i,:-1]
#学习这种判定模式
result[i-1, :-1] = np.mean(oneCluster, axis= 0)
result[i-1, -1] = i
return result
x1 = np.array([1,1])
x2 = np.array([2,1])
x3 = np.array([4,3])
x4 = np.array([5,4])
testX = np.vstack((x1, x2, x3, x4))
print testX
result = Kmeans(testX,2,10)
print "final result:"
print result
- 优缺点:
通过以上代码,我们可以发现,必须要提前确定K值,而在实际操作中是不可能确定的。
但是,优点也较为明显:速度快,简单