【机器学习】 k-means聚类算法
k-means算法原理
输入:类簇个数K,迭代终止条件
for m ← 1 to M:
//M是数据集中数据的个数
for k ← 1 to K:
//k是各类簇的中心点
保留到m欧式距离最近的k,将m归入k簇
while 不达到终止阈值θ:
计算各类簇的新中心点k,中心点k为k类簇各点的均值
for m ← 1 to M:
for k ← 1 to K:
保留到m欧式距离最近的k,将m归入k簇
计算是否达到终止条件
输出:聚类结果
关于终止条件:
- 一般终止条件为每个数据归属的簇不再变化,或k-means算法的损失函数变化小于某一阈值
- k-means算法的损失函数为:
其中 是每个簇中所有的点, 是k这个簇的聚类中心
k-means算法的两个大问题是:
- 第一次聚类中心的选取
- 聚类中心个数k的选取
k-means算法python实现
# -*- coding:utf-8 -*-
import random
import numpy as np
import math
import matplotlib.pylab as plt
def create_the_dataset(size, min, max):
# 随机生成数据集,size是数据集的大小,min是点坐标的最小值,max是点坐标的最大值
dataset = []
sub_dataset = []
for i in range(size):
sub_dataset.append(random.uniform(min, max))
sub_dataset.append(random.uniform(min, max))
dataset.append(sub_dataset)
sub_dataset = []
dataset = np.mat(dataset)
# 将列表变成矩阵
# 数据集是(size,2)的矩阵
return dataset
def get_euclidean_distance(point, center):
# 计算两个点的欧式距离
# 输入是两个(1,2)的矩阵
# np.power((矩阵1-矩阵2),2)分别计算两个矩阵每一列相减后的二次方,结果是一个(1,2)的矩阵
euclidean_distance = math.sqrt(np.sum(np.power((point - center), 2)))
return euclidean_distance
def initialize_the_center(dataset, k):
# 生成聚类中心,dataset是矩阵数据类型的数据集,k是要生成的聚类中心的数量
center = np.mat(np.zeros((k, 2)))
for i in range(2):
Range = float(max(dataset[:, i]) - min(dataset[:, i]))
# 矩阵某一列的范围,也就是(最大值-最小值)
center[:, i] = min(dataset[:, i]) + Range * np.random.rand(k, 1)
# 对应这列的k个值是这列的(最小值+范围×随机生成的一组符合0到1之间的均匀分布的系数)
# 中心是(k,2)的矩阵
return center
def visualization(center, clusterAssment, dataset):
# 画点
dataset = dataset.tolist()
center = center.tolist()
clusterAssment = clusterAssment.tolist()
# 将数据变成列表类型
color = ['red', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna',
'silver', 'skyblue', 'slateblue', 'slategray', 'snow', '#FFFAFA', 'springgreen', 'steelblue', 'tan',
'teal', 'thistle']
x = []
y = []
for i in range(len(center)):
x.append(center[i][0])
y.append(center[i][1])
plt.scatter(x, y, color=color[i], s=40)
x = []
y = []
for j, each in enumerate(clusterAssment):
if each[0] == i:
x.append(dataset[j][0])
y.append(dataset[j][1])
plt.scatter(x, y, color=color[i+1], s=40)
x = []
y = []
plt.savefig("k-means.png")
plt.show()
def kmeans(size, min, max, k):
# k-means算法的实现
# size是数据集的大小,min是点坐标的最小值,max是点坐标的最大值,k是选取的聚类中心的个数
dataset = create_the_dataset(size, min, max)
# 生成数据集
center = initialize_the_center(dataset, k)
# 初始化聚类中心
clusterAssment = np.mat(np.zeros((size, 2)))
# (size,2)的矩阵,用于判断每个数据归属的聚类中心是否还发生变化
# 每一行第一列是聚类中心的序号,第二列是到聚类中心的距离
clusterChanged = True
while clusterChanged:
clusterChanged = False
for i in range(size):
minDist = np.inf
# 对于每一个数据,先设置最小距离是无限大
minIndex = -1
# 设置离它最近的点序号是-1
for j in range(k):
distJI = get_euclidean_distance(dataset[i, :], center[j, :])
# 计算一个数据和一个聚类中心的欧式距离
if distJI < minDist:
# 保留最小的那个欧式距离和对应的聚类中心序号
minDist = distJI
minIndex = j
if clusterAssment[i, 0] != minIndex:
# 如果其中一个聚类中心变化了,就继续循环
clusterChanged = True
clusterAssment[i, :] = minIndex, minDist ** 2
for cent in range(k):
# 更新聚类中心
dataCent = dataset[np.nonzero(clusterAssment[:, 0].A == cent)[0]]
# clusterAssment[:, 0].A将(size,1)的矩阵变成size行1列的tuple
# clusterAssment[:, 0].A中每行和cent比较,相等返回True,不想等返回False
# np.nonzero返回为True的索引(非零元素的索引)
# 因为dataset和clusterAssment是一一对应的,所以通过clusterAssment索引到每类的每个数据
center[cent, :] = np.mean(dataCent, axis=0)
# axis=0是普通的将每一列相加,而axis=1表示的是将向量的每一行进行相加
visualization(center,clusterAssment, dataset)
# 返回聚类中心center(k,2)的矩阵,每行是坐标
# 返回聚类结果clusterAssment(size,2)的矩阵,每行第一列是归属类的序号,第二列是点到中心的距离
return center, clusterAssment
def main():
_, _ = kmeans(200, 0, 10, 4)
if __name__ == "__main__":
main()
聚类结果:
sklearn中的k-means算法
sklearn库中有封装好的k-means算法
# -*- coding:utf-8 -*-
import random
import numpy as np
import matplotlib.pylab as plt
from sklearn.cluster import KMeans
def create_the_dataset(size, min, max):
# 随机生成数据集,size是数据集的大小,min是点坐标的最小值,max是点坐标的最大值
dataset = []
sub_dataset = []
for i in range(size):
sub_dataset.append(random.uniform(min, max))
sub_dataset.append(random.uniform(min, max))
dataset.append(sub_dataset)
sub_dataset = []
dataset = np.mat(dataset)
# 将列表变成矩阵
# 数据集是(size,2)的矩阵
return dataset
def kmeans(size, min, max, k):
# k-means算法的实现
# size是数据集的大小,min是点坐标的最小值,max是点坐标的最大值,k是选取的聚类中心的个数
dataset = create_the_dataset(size, min, max)
# 生成数据集
y_pred = KMeans(n_clusters=k).fit_predict(dataset)
plt.scatter(dataset[:, 0].tolist(), dataset[:, 1].tolist(), c=y_pred)
plt.savefig("k-means.png")
plt.show()
def main():
kmeans(200, 0, 10, 4)
if __name__ == "__main__":
main()
聚类结果:
参数:
sklearn.cluster.KMeans(n_clusters=8, init='k-means++', n_init=10, max_iter=300, tol=0.0001, precompute_distances='auto', verbose=0, random_state=None, copy_x=True, n_jobs=1)
- n_clusters:聚类中心个数的选择
- init:用"k-means++"还是用"random"初始化聚类中心
- n_init:跑k-means的次数,最后选择最好的结果作为最后结果
- max_iter:跑一次k-means的最大迭代次数
- random_state: 如果给出整数,随机初始化聚类中心将固定种子
使用方法:
- fit(X[, y]):Compute k-means clustering.
- fit_predict(X[, y]):Compute cluster centers and predict cluster index for each sample.
- fit_transform(X[, y]):Compute clustering and transform X to cluster-distance space.
- get_params([deep]):Get parameters for this estimator.
- predict(X):Predict the closest cluster each sample in X belongs to.
- score(X[, y]):Opposite of the value of X on the K-means objective.
- set_params(**params):Set the parameters of this estimator.
- transform(X[, y]):Transform X to a cluster-distance space.
官方文档:http://lijiancheng0614.github.io/scikit-learn/modules/generated/sklearn.cluster.KMeans.html
关于k-means++:
k-means++算法选择初始聚类中心的基本思想就是:初始的聚类中心之间的相互距离要尽可能的远。
- 从输入的数据点集合中随机选择一个点作为第一个聚类中心
- 对于数据集中的每一个点x,计算它与最近聚类中心(指已选择的聚类中心)的距离D(x)
- 选择一个新的数据点作为新的聚类中心,选择的原则是:D(x)较大的点,被选取作为聚类中心的概率较大
- 重复2和3直到k个聚类中心被选出来
- 利用这k个初始的聚类中心来运行标准的k-means算法
参考来源:https://blog.csdn.net/chlele0105/article/details/12997391
结语
如果您有修改意见或问题,欢迎留言或者通过邮箱和我联系。
手打很辛苦,如果我的文章对您有帮助,转载请注明出处。