kmeans算法的k值选择

确定 K 值是 K-means 聚类分析的一个重要步骤。不同的 K 值可能会产生不同的聚类结果,因此选择合适的 K 值非常重要。

以下是一些常见的方法来选择 K 值:

  • 手肘法:该方法基于绘制聚类内误差平方和(SSE)与 K 值之间的关系图。随着 K
    值的增加,SSE会逐渐降低,但降低幅度逐渐减小。手肘法的目标就是找到 SSE 下降的速度开始变慢的“拐点”,这个点就是最佳的 K 值。
  • 轮廓系数法:该方法基于每个数据点与它所属的聚类中心的距离和与它邻近的聚类中心的距离之间的比值计算出轮廓系数。对于一个合适的 K值,它的轮廓系数应该最大。
  • Gap 统计量法:该方法比较聚类结果和一组随机数据集的聚类结果之间的差异。Gap 统计量越大,表示聚类结果越好。
  • Silhouette 统计量法:该方法将每个数据点的轮廓系数加权平均,作为整个聚类的 Silhouette统计量。与轮廓系数法类似,Silhouette 统计量也应该最大化。

手肘法

from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import numpy as np

# 导入数据集
X = np.loadtxt('wholesale_customers_data.csv', delimiter=',', skiprows=1)

# 定义 SSE 函数
def sse(X, k):
    kmeans = KMeans(n_clusters=k)
    kmeans.fit(X)
    return kmeans.inertia_

# 定义 K 值的范围
k_range = range(1, 11)

# 计算每个 K 值对应的 SSE
sse_list = [sse(X, k) for k in k_range]

# 绘制 SSE 与 K 值之间的关系图
plt.plot(k_range, sse_list)
plt.xlabel('K')
plt.ylabel('SSE')
plt.show()

# 找到手肘点并将其打印出来
diffs = np.diff(sse_list)
elbow_point = k_range[np.argmax(diffs) + 1]
print(f"The elbow point is at K = {
      
      elbow_point}")

1、X = np.loadtxt(‘wholesale_customers_data.csv’, delimiter=‘,’, skiprows=1)

使用 NumPy 库中的 loadtxt() 函数从 CSV 文件中加载数据集。具体来说,该函数将 CSV 文件中的每一行视为一个样本,每一列视为一个特征,并将它们存储在一个 NumPy 数组中。

该函数的参数包括:

  • fname: 要加载的文件名。
  • delimiter: 文件中列之间的分隔符。在这个例子中,我们将逗号作为分隔符。
  • skiprows: 要跳过的行数。在这个例子中,我们将跳过文件的第一行,因为第一行是标题行,而不是数据行。

因此,X = np.loadtxt(‘wholesale_customers_data.csv’, - delimiter=‘,’, skiprows=1) 这行代码的作用是将 Wholesale customers 数据集从 CSV 文件中加载到名为 X 的 NumPy 数组中,以便用于后续的聚类分析。

kmeans.inertia_

kmeans.inertia_ 是 KMeans 聚类算法中的一个属性,它表示聚类模型的 SSE(Sum of Squared Errors,平方误差和),即所有数据点到其所属簇质心的距离平方和。SSE 是一个衡量聚类效果的指标,其值越小表示聚类效果越好。

在 KMeans 聚类算法中,我们的目标是找到 SSE 最小的聚类方案。kmeans.inertia_ 属性返回当前聚类方案的 SSE 值,因此我们可以通过计算不同 K 值下的 SSE 值来选择最佳的 K 值,以达到最优的聚类效果。

diffs = np.diff(sse_list)

np.diff() 函数是 NumPy 库中的一个函数,用于计算一个数组中相邻元素之间的差异。具体来说,该函数返回一个新数组,其中每个元素是原始数组中相邻元素之间的差值。

在聚类分析中,我们通常会使用 SSE(Sum of Squared Errors,平方误差和)指标来衡量聚类质量。在手肘法中,我们需要找到一个 K 值,使得 SSE 在这个 K 值之后的下降速度开始变慢,形成一个“手肘”状的曲线。因此,我们需要计算不同 K 值下的 SSE,然后找到相邻 SSE 之间的差异,以便找到手肘点的位置。

在这个代码行中,np.diff(sse_list) 的作用是计算 SSE 列表中相邻元素之间的差异,将它们存储在一个新数组 diffs 中。然后,我们将 diffs 用于找到手肘点的位置,即 SSE 减少速度开始变慢的位置。

elbow_point = k_range[np.argmax(diffs) + 1]

k_range 是一个包含了我们尝试的 K 值的列表,diffs 是一个包含相邻 SSE 差异的列表。我们需要找到一个 K 值,使得 SSE 下降的速度开始变慢,也就是在这个 K 值之后,SSE 减少的程度变小。因此,我们需要找到 diffs 中最大值的位置,然后将其加 1,就能得到手肘点的位置。

具体来说,np.argmax(diffs) 返回 diffs 数组中最大值的索引,也就是 SSE 下降速度开始变慢的位置。我们将它加 1 的原因是,由于 diffs 是通过计算相邻 SSE 之间的差异得到的,因此它的长度比 k_range 小 1,需要将其索引值加 1,以便在 k_range 中找到相应的 K 值。

最终,elbow_point = k_range[np.argmax(diffs) + 1] 将手肘点的 K 值赋值给 elbow_point 变量。

SSE

SSE(Sum of Squared Errors,平方误差和)是 KMeans 聚类算法中的一个指标,用于评估聚类模型的拟合程度。SSE 表示所有数据点到其所属簇质心的距离平方和。

在 KMeans 聚类算法中,我们的目标是将数据点划分到 K 个簇中,使得簇内的数据点尽量相似,而不同簇之间的数据点尽量不相似。这个过程中,我们需要对每个簇计算其质心(即簇内所有数据点的平均值),然后将每个数据点划分到距离它最近的簇中。

SSE 表示每个数据点到其所属簇质心的距离平方和。具体来说,对于每个数据点 i i i 和其所属簇质心 c i c_i ci,其 SSE 贡献为:
在这里插入图片描述
其中 n n n 表示数据点的总数, ∣ ∣ x i − c i ∣ ∣ ||\mathbf{x_i} - \mathbf{c_i}|| ∣∣xici∣∣ 表示数据点 i i i 到其所属簇质心 c i c_i ci 的欧几里得距离。最终的 SSE 值就是所有数据点的 SSE 贡献之和:
![
因为 SSE 表示每个数据点到其所属簇质心的距离平方和,所以它越小,表示聚类效果越好,即数据点与所属簇的质心越接近。因此,在 KMeans 聚类算法中,我们的目标是找到 SSE 最小的聚类方案。

SSEi和distances=np.sqrt(((X-self.centers[:,np.newaxis])**2).sum(axis=2))的distances区别?

SSE_i 是数据点 i i i 到其所属簇质心的距离平方和,是一个标量值。

distances 是一个二维数组,其中第 i i i 行第 j j j 列的元素表示数据点 i i i 到质心 j j j 的欧几里得距离。它的计算方式是对数据集 X 中所有数据点和质心之间的欧几里得距离进行计算。这里的 X 是数据集,self.centers 是聚类过程中计算出的质心,np.newaxis 是为了方便进行广播操作。

在 KMeans 算法中,我们需要将每个数据点划分到距离它最近的簇中。为了实现这一点,我们需要计算每个数据点到所有质心的距离,然后选取距离最小的质心作为该数据点所属簇的质心。因此,distances 数组在实现 KMeans 算法中起到了关键作用。

在代码中,distances 的计算方式是将数据集 X 中的每个数据点减去所有质心,然后求得每个数据点到所有质心的距离。而 SSE_i 的计算方式是对每个数据点和其所属簇质心之间的距离进行计算,然后将所有距离平方和起来。因此,它们的计算方式是不同的,但都在计算 KMeans 算法中的距离相关指标。

轮廓系数法

from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
import numpy as np

# 加载数据集
X = np.loadtxt('wholesale_customers_data.csv', delimiter=',', skiprows=1)

# 设置需要尝试的 K 值范围
k_range = range(2, 11)

# 保存每个 K 值对应的轮廓系数
silhouette_scores = []

for k in k_range:
    # 初始化 KMeans 聚类器
    kmeans = KMeans(n_clusters=k)

    # 训练 KMeans 模型
    kmeans.fit(X)

    # 计算轮廓系数
    score = silhouette_score(X, kmeans.labels_)
    silhouette_scores.append(score)

# 打印轮廓系数最大的 K 值
best_k = k_range[np.argmax(silhouette_scores)]
print(f"Best K value: {
      
      best_k}")

计算轮廓系数

score = silhouette_score(X, kmeans.labels_)
silhouette_scores.append(score)

在轮廓系数法中,我们使用轮廓系数来评估聚类结果的质量。轮廓系数计算了每个数据点与它所属的聚类中心的距离 a i a_i ai 以及与它邻近的聚类中心的距离 b i b_i bi,并将它们的比值 ( b i − a i ) / m a x ( a i , b i ) (b_i - a_i) / max(a_i, b_i) (biai)/max(ai,bi) 作为该数据点的轮廓系数。

在代码中,我们使用 silhouette_score 函数来计算轮廓系数。

  • 该函数的第一个参数是数据集 X,第二个参数是 KMeans 模型的 labels_ 属性,该属性保存了每个数据点所属的聚类标签。
  • 该函数返回整个数据集的平均轮廓系数,我们将其添加到 silhouette_scores 列表中。

最后,我们将轮廓系数最大的 K 值作为最佳的聚类数。

Silhouette 统计量法

from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

silhouette_scores = []

for k in k_range:
    kmeans = KMeans(n_clusters=k, random_state=42)
    kmeans.fit(X)
    
    # 计算每个数据点的轮廓系数
    score = silhouette_score(X, kmeans.labels_)
    
    # 计算整个聚类的 Silhouette 统计量
    silhouette_scores.append(score)

# 选择具有最大 Silhouette 统计量的 k 值
best_k = k_range[np.argmax(silhouette_scores)]

在上述代码中,我们使用 Scikit-learn 中的 KMeans 类来运行 KMeans 聚类算法,并计算每个数据点的轮廓系数。最后,我们计算加权平均轮廓系数,作为整个聚类的 Silhouette 统计量,并选择具有最大 Silhouette 统计量的 k 值。

Gap 统计量法

from sklearn.cluster import KMeans
import numpy as np
import math

# 加载数据集
X = np.loadtxt('wholesale_customers_data.csv', delimiter=',', skiprows=1)

# 设置需要尝试的 K 值范围
k_range = range(1, 11)

# 计算原始数据的总平均对数误差
log_Wk = []
for k in k_range:
    kmeans = KMeans(n_clusters=k)
    kmeans.fit(X)
    log_Wk.append(math.log(kmeans.inertia_))

# 计算 Gap 统计量
gaps = []
for k in k_range:
    # 生成 B 个参考数据集
    B = 10
    BWs = np.zeros(B)
    for i in range(B):
        # 生成符合原始数据特征的随机数据集
        Xb = np.random.uniform(low=X.min(axis=0), high=X.max(axis=0), size=X.shape)

        # 训练 KMeans 模型,并计算对数误差
        kmeans = KMeans(n_clusters=k)
        kmeans.fit(Xb)
        BWs[i] = math.log(kmeans.inertia_)

    # 计算 Gap 统计量
    gap = np.mean(BWs) - log_Wk[k-1]
    gaps.append(gap)

# 找到 Gap 统计量最大的 K 值
best_k = np.argmax(gaps) + 1
print(f"Best K value: {
      
      best_k}")

在 Gap 统计量法中,我们需要计算 Gap 统计量。计算 Gap 统计量的步骤
  • 首先,我们需要在数据集上运行 KMeans 聚类算法,对于每个 k 值,我们都会得到一个聚类模型和相应的 SSE 值。

  • 接下来,我们需要生成一些随机数据集。这些数据集应该和原始数据集具有相同的大小和特征,但是它们是在某种程度上随机的。例如,我们可以使用在每个特征上均匀分布的随机值来创建随机数据集。我们通常需要生成多个这样的随机数据集。

  • 对于每个随机数据集,我们重复第一步的聚类过程,并计算每个 k 值下的 SSE。

  • 对于每个 k 值,我们计算 Gap 统计量。Gap 统计量是随机数据集 SSE 的均值减去原始数据集 SSE,并用一个标准差调整。标准差的计算方法如下:

std_k = sqrt(1 + 1/n_ref) * std_ref_k

其中,n_ref 是生成的随机数据集的数量,std_ref_k 是在 k 值下随机数据集 SSE 的标准差。

  • 最后,我们选择一个合适的 k 值,它的 Gap 统计量应该最大。

猜你喜欢

转载自blog.csdn.net/m0_62865498/article/details/130517030