监督式学习的训练集是带label的,比如下图中的圈圈和叉叉,分别代表“正”数据集和“负”数据集,监督式学习的目标是找到一个可以分开这两个数据集的decision boundary。
相反,非监督式学习的训练集是没有带任何标签的。如下图所示,数据集是没有带任何标签,需要非监督式学习算法找到训练数据集的近似点,将相似的对象归到同一个聚类中。其中一种就是聚类算法。
K-means算法一个典型的聚类算法,将相似的数据对象归到同一簇中,将不相似的对象归到不同簇中。
K-means算法流程大概如下,随机选取K个初始点作为聚类中心,遍历每个点,寻找其与最近的聚类中心,并将该点分配到该聚类中心所在的簇。接着,分别计算每个簇的平均值,更新k个聚类中心。K-means算法演示如下:
K-means算法的伪代码:
没有明显区分的簇群的数据,K-means算法也可以很好地将数据分开,如下图所示的体重和身高数据集,利用K-means算法根据这些数据集将T恤的大小分为三类,S,M,L。
K-means 的目标优化函数cost function 是基于最小误差平方和准则。
其中μc(i)代表与x(i)最近的聚类中心点。优化目标是试图找到c(1),c(2),...,c(m)和μ1,μ2,...,μk使得目标函数最小。直观来说,就是各簇的数据越相似,与该簇的聚类中心的距离就越小,数据跟聚类中心的误差平方越小。
在上面的 K-means伪代码中,第一步是随机初始化K个聚类中心。如何随机初始化?首先保证K<m,即聚类中心的个数K要小于训练数据集m。然后随机抽取训练集的K个数据作为聚类中心。
由于聚类中心是随机选取的,如下图所示,如果随机选取的好,那么数据的聚类效果就很好,但如果随机选取的不好,那可能结果并不是我们想要的。
为了避免这种情况,通常采取的策略是多次运行K-means算法,选取优化目标函数最小的情况作为最后结果。算法的伪代码如下。
由于K-means算法的K的值是必须预先设定的,如何设定K值,第一种方法可以根据不同K值算出优化目标函数值,画出K-J曲线,选取拐点的那个K值。
如果没有出现拐点,那就根据具体聚类的目的来选取,比如对衣服尺码进行聚类分析,如果你把尺码定为S,M,L,那K就选3;如果你把尺码定为XS,S,M,L,XL,那K选取5。
K-means代码是从zouxy09参考过来的,做了一些稍微的修改
import pdb
from numpy import *
import time
import matplotlib.pyplot as plt
# show your cluster only available with 2-D data
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! please contact Zouxy"
return 1
# draw all samples
for i in xrange(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']
# draw the centroids
for i in range(k):
plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize = 12)
plt.show()
# calculate Euclidean distance
def euclDistance(vector1, vector2):
return sqrt(sum(power(vector2 - vector1, 2)))
# init centroids with random samples
def initCentroids(dataSet, k):
numSamples, dim = dataSet.shape
centroids = zeros((k, dim))
for i in range(k):
index = int(random.uniform(0, numSamples))
centroids[i, :] = dataSet[index, :]
return centroids
# k-means cluster
def kmeans(dataSet, k):
numSamples = dataSet.shape[0]
# first column stores which cluster this sample belongs to,
# second column stores the error between this sample and its centroid
clusterAssment = mat(zeros((numSamples, 2)))
clusterChanged = True
## step 1: init centroids
centroids = initCentroids(dataSet, k)
showCluster(dataSet, k, centroids, clusterAssment)
##pdb.set_trace()
while clusterChanged:
clusterChanged = False
## for each sample
for i in xrange(numSamples):
minDist = 100000.0
minIndex = 0
## for each centroid
## step 2: find the centroid who is closest
for j in range(k):
distance = euclDistance(centroids[j, :], dataSet[i, :])
if distance < minDist:
minDist = distance
minIndex = j
## step 3: update its cluster
if clusterAssment[i, 0] != minIndex:
clusterChanged = True
clusterAssment[i, :] = minIndex, minDist**2
## step 4: update centroids
for j in range(k):
pointsInCluster = dataSet[nonzero(clusterAssment[:, 0].A == j)[0]]
centroids[j, :] = mean(pointsInCluster, axis = 0)
showCluster(dataSet, k, centroids, clusterAssment)
print 'Congratulations, cluster complete!'
return centroids, clusterAssment
if __name__ == '__main__':
## step 1: load data
print "step 1: load data..."
dataSet = []
fileIn = open('C://Python27/test/testSet.txt')
for line in fileIn.readlines():
lineArr = line.strip().split('\t')
dataSet.append([float(lineArr[0]), float(lineArr[1])])
#pdb.set_trace()
## step 2: clustering...
print "step 2: clustering..."
dataSet = mat(dataSet)
k = 4
centroids, clusterAssment = kmeans(dataSet, k)
## step 3: show the result
print "step 3: show the result..."
showCluster(dataSet, k, centroids, clusterAssment)
参考资料
1、http://www.ryanzhang.info/archives/1213
2、http://blog.csdn.net/zouxy09/article/details/17589329
3、https://class.coursera.org/ml-007
4、《Machine Learning in Action》
5、http://coolshell.cn/articles/7779.html
6、http://www.cnblogs.com/leoo2sk/archive/2010/09/20/k-means.html
7、http://blog.pluskid.org/?page_id=78漫谈 Clustering 系列很赞的博文