欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

k-means、DBSCAN聚类算法代码

程序员文章站 2022-05-20 19:37:17
...

k-means聚类算法

优点

容易实现。
适用于高维。

缺点

对离群点敏感,对噪声点和孤立点很敏感。
不适用于非凸的簇或大小差别很大的簇。
需要自定义k,不同的初始点可能得到的结果完全不同。
可能收敛到局部最小值,在大规模数据集上收敛较慢。

适用数据类型

数值型数据。

伪代码

创建k个点作为起始质心(经常是随机选择)
当任意一个点的簇分配结果发生改变时
	对数据集中的每个数据点
		对每个质心
			计算质心与数据点之间的距离
		将数据点分配到距其最近的簇
	对每一个簇,计算簇中所有点的均值并将均值作为质心

k-means代码

from numpy import *

def loadDataSet(fileName):  # 将文本文件导入到列表
    dataMat = []
    fr = open(fileName)
    for line in fr.readlines():
        curLine = line.strip().split('\t')
        fltLine = list(map(float, curLine))  # 需要在此处将map结果转化为列表
        dataMat.append(fltLine)
    return dataMat

def distEclud(vecA, vecB):  # 计算两个向量的欧式距离
    return sqrt(sum(power(vecA - vecB, 2)))

def randCent(dataSet, k):  # 为给定的数据集构建一个包含k个质心的集合
    n = shape(dataSet)[1]
    centroids = mat(zeros((k, n)))
    for j in range(n):  # 随机质心必须要在整个数据集的边界之内
        minJ = min(dataSet[:, j])  # 可以通过找到数据集每一维德最小和最大值来完成
        rangeJ = float(max(dataSet[:, j]) - minJ)
        centroids[:, j] = minJ + rangeJ * random.rand(k, 1)
    return centroids

def kMeans(dataSet, k, distMeas=distEclud, createCent=randCent):
    m = shape(dataSet)[0]  # 样本数
    clusterAssment = mat(zeros((m, 2)))  # 创建一个矩阵,存储每个点的簇分配结果(一列记录簇索引值,另一列存储误差)
    centroids = createCent(dataSet, k)  # 初始化k个质心
    clusterChanged = True
    while clusterChanged:
        clusterChanged = False
        for i in range(m):  # 遍历每一个样本
            minDist = inf
            minIndex = -1
            for j in range(k):  # 对当前样本找到离其最近的质心
                distJI = distMeas(centroids[j, :], dataSet[i, :])
                if distJI < minDist:
                    minDist = distJI
                    minIndex = j
            if clusterAssment[i, 0] != minIndex:  # 簇分配仍在进行
                clusterChanged = True
            clusterAssment[i, :] = minIndex, minDist ** 2
        print(centroids)
        for cent in range(k):  # 更新质心的位置
            ptsInClust = dataSet[nonzero(clusterAssment[:, 0].A==cent)[0]]  # 每个簇中样本的值
            centroids[cent, :] = mean(ptsInClust, axis=0)  # 求每个簇的均值
    return centroids, clusterAssment

dataMat = mat(loadDataSet('testSet.txt'))  # 将文本文件导入到列表,再将列表转换为矩阵
myCentroids, clusterAssing = kMeans(dataMat, 4)
结果:经过3次迭代,算法就已经收敛。

k-means、DBSCAN聚类算法代码
最终分簇结果如图所示:
k-means、DBSCAN聚类算法代码

聚类度量指标SSE

SSE(Sum of Squared Error,误差平方和)。SSE越小表示数据点越接近它们的质心,聚类效果也就越好。因为对误差取了平方,因此更加重视那些远离中心的点。

k-均值很容易会收敛到局部最小值,而二分k-均值算法能在相似的思想上达到更好的聚类效果。

二分k-均值算法

为克服K-均值算法收敛于局部最小值的问题,有人提出了二分k-均值的算法。该算法首先将所有点作为一个簇,然后将该簇一分为二。之后选择其中一个簇继续进行划分,选择哪一个簇取决于对其划分是否可以最大程度降低SSE的值。上述基于SSE的划分过程不断重复,知道得到用户指定的簇数目为止。

二分k-均值算法伪代码

将所有点看成一个簇
当簇数目小于k时
	对于每一个簇
		计算总误差
		在给定的簇上面进行k-均值聚类(k=2)
		计算将该簇一分为二之后的总误差
	选择是的误差最小的那个簇进行划分操作

代码参考链接:https://www.cnblogs.com/multhree/p/11279140.html

k-means与DBSCAN效果对比

k-means

k-means、DBSCAN聚类算法代码

k-means、DBSCAN聚类算法代码

DBSCAN

k-means、DBSCAN聚类算法代码

k-means

k-means、DBSCAN聚类算法代码
k-means、DBSCAN聚类算法代码

DBSCAN

k-means、DBSCAN聚类算法代码

K-Means++、Mini Bacth K-Means

因为K-Means算法对初次选取的类别中心敏感,不同的随机种子点得到的聚类结果会有不同。K-Means++算法便是在K-Means的基础上解决了这个问题,并不是一开始就把所有初始点找到,而是一个个地找初始点。这样达到的效果就是:初始的聚类中心之间的相互距离会比较远

Mini Bacth K-Means算法:使用分批处理(Mini Bacth)的方法对数据点之间的距离进行计算。当样本点较多时,直接使用K-Means算法进行聚类的话,效率会比较慢,每一轮都有遍历计算所有的样本点到各个聚类中心的距离。

Mini Bacth K-Means的好处在于:不必使用所有的样本点进行距离计算、而是每次使用一个batch的样本点来进行K-means算法,进行计算到各个聚类中心的距离,从而得到新的聚类中心。batch_size的大小需自定义。
由于计算样本量的减少,相应的运行时间也会减少,但会带来准确度的降低

算法比较

from sklearn.cluster import KMeans, MiniBatchKMeans

centers = [[1, 0], [-1, 0], [0, -1], [0, 1], [0, 0], [-0.7, -0.7], [-0.7, 0.7], [0.7, -0.7], [0.7, 0.7]]
X, y_true = make_blobs(n_samples=100000, centers=centers, cluster_std=0.18, random_state=0)
fig, axes = plt.subplots(2, 2)
axes[0, 0].scatter(X[:, 0], X[:, 1], c=y_true)
axes[0, 0].set_xlabel('y_true')

t0 = time.time()
y_pred1 = KMeans(init='random', n_clusters=9, random_state=666, n_init=1).fit_predict(X)
t_k_means = time.time() - t0
axes[0, 1].scatter(X[:, 0], X[:, 1], c=y_pred1)
axes[0, 1].set_xlabel('k-means time:%f'%t_k_means)

y_pred2 = KMeans(init='k-means++', n_clusters=9, random_state=666, n_init=1).fit_predict(X)
axes[1, 0].scatter(X[:, 0], X[:, 1], c=y_pred2)
axes[1, 0].set_xlabel('k-means++')

t0 = time.time()
y_pred3 = MiniBatchKMeans(init='random', n_clusters=9, batch_size=900, n_init=1, max_no_improvement=10).fit_predict(X)
t_batch_means = time.time() - t0
axes[1, 1].scatter(X[:, 0], X[:, 1], c=y_pred3)
axes[1, 1].set_xlabel('batch-k-means time:%f'%t_batch_means)

plt.subplots_adjust(left=0.2, bottom=0.2, right=0.8, top=0.8, hspace=0.9, wspace=0.9)
plt.show()

结果如图所示:
k-means、DBSCAN聚类算法代码

层次聚类与DBSCAN

代码参考:https://blog.csdn.net/sinat_18665801/article/details/90637272