确定 K 值是 K-means 聚类分析的一个重要步骤。不同的 K 值可能会产生不同的聚类结果,因此选择合适的 K 值非常重要。
以下是一些常见的方法来选择 K 值:
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}")
使用 NumPy 库中的 loadtxt() 函数从 CSV 文件中加载数据集。具体来说,该函数将 CSV 文件中的每一行视为一个样本,每一列视为一个特征,并将它们存储在一个 NumPy 数组中。
该函数的参数包括:
因此,X = np.loadtxt(‘wholesale_customers_data.csv’, - delimiter=‘,’, skiprows=1) 这行代码的作用是将 Wholesale customers 数据集从 CSV 文件中加载到名为 X 的 NumPy 数组中,以便用于后续的聚类分析。
kmeans.inertia_ 是 KMeans 聚类算法中的一个属性,它表示聚类模型的 SSE(Sum of Squared Errors,平方误差和),即所有数据点到其所属簇质心的距离平方和。SSE 是一个衡量聚类效果的指标,其值越小表示聚类效果越好。
在 KMeans 聚类算法中,我们的目标是找到 SSE 最小的聚类方案。kmeans.inertia_ 属性返回当前聚类方案的 SSE 值,因此我们可以通过计算不同 K 值下的 SSE 值来选择最佳的 K 值,以达到最优的聚类效果。
np.diff() 函数是 NumPy 库中的一个函数,用于计算一个数组中相邻元素之间的差异。具体来说,该函数返回一个新数组,其中每个元素是原始数组中相邻元素之间的差值。
在聚类分析中,我们通常会使用 SSE(Sum of Squared Errors,平方误差和)指标来衡量聚类质量。在手肘法中,我们需要找到一个 K 值,使得 SSE 在这个 K 值之后的下降速度开始变慢,形成一个“手肘”状的曲线。因此,我们需要计算不同 K 值下的 SSE,然后找到相邻 SSE 之间的差异,以便找到手肘点的位置。
在这个代码行中,np.diff(sse_list) 的作用是计算 SSE 列表中相邻元素之间的差异,将它们存储在一个新数组 diffs 中。然后,我们将 diffs 用于找到手肘点的位置,即 SSE 减少速度开始变慢的位置。
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(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}|| ∣∣xi−ci∣∣ 表示数据点 i i i 到其所属簇质心 c i c_i ci 的欧几里得距离。最终的 SSE 值就是所有数据点的 SSE 贡献之和:
因为 SSE 表示每个数据点到其所属簇质心的距离平方和,所以它越小,表示聚类效果越好,即数据点与所属簇的质心越接近。因此,在 KMeans 聚类算法中,我们的目标是找到 SSE 最小的聚类方案。
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) (bi−ai)/max(ai,bi) 作为该数据点的轮廓系数。
在代码中,我们使用 silhouette_score 函数来计算轮廓系数。
最后,我们将轮廓系数最大的 K 值作为最佳的聚类数。
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 值。
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}")
首先,我们需要在数据集上运行 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 的标准差。