目录
- 写在开头
- 1. K均值算法基础
- 1.1 什么是K均值算法?
- 1.2 K均值算法的工作原理
- 1.3 算法的优势与局限性
- 2. K均值算法的实现步骤
- 2.1 初始聚类中心的选择方法
- 2.1.1 随机选择初始中心点
- 2.1.2 K均值++算法
- 2.2 数据点与聚类中心的距离计算
- 2.2.1 欧氏距离计算
- 2.2.2 曼哈顿距离计算
- 2.3 更新聚类中心
- 2.4 重复迭代直至收敛
- - K均值在Python中的应用
- 3.1 Python中的K均值算法库
- 3.2 数据准备与预处理
- 3.3 调用算法进行聚类
- 3.4 结果可视化与分析
- 4. K均值算法的参数调优与改进
- 4.1 如何选择合适的K值?
- 4.1.1 肘部法则(Elbow Method)
- 4.1.2 轮廓系数法
- 4.2 改进K均值算法的方法
- 4.2.1 基于密度的聚类
- 4.2.2 高斯混合模型
- 4.2.3 实际案例分析与效果评估
- 4.3 实际案例
- 写在最后
写在开头
聚类算法是数据科学中的重要工具,而K均值算法则是其中的一颗璀璨明珠。本篇博客将带您深入了解K均值算法的原理、实现步骤,并通过Python实例展示其在实际项目中的应用与调优技巧。
1. K均值算法基础
1.1 什么是K均值算法?
K均值算法是一种无监督学习的聚类算法,用于将数据集中的数据点划分为K个簇,使得每个簇内的数据点相似度较高,而不同簇之间的相似度较低。其目标是通过最小化簇内数据点与其对应聚类中心的距离的平方和,来实现对数据的有效分组。
算法的执行过程如下:
- 选择K个初始聚类中心,可以是随机选择或采用特定的初始化方法,如K均值++算法。
- 将每个数据点分配到最近的聚类中心所属的簇。
- 更新每个簇的中心位置,将其移动到簇内所有数据点的平均位置。
- 重复以上两步,直至聚类中心不再发生明显变化或达到预定的迭代次数。
1.2 K均值算法的工作原理
K均值算法的工作原理可以概括为以下几个关键步骤:
步骤1:选择初始聚类中心
- K均值算法开始时需要选择K个初始聚类中心。这可以通过随机选择数据集中的K个点或使用更智能的初始化方法,如K均值++算法。
步骤2:分配数据点到最近的聚类中心
- 对于每个数据点,计算其与每个聚类中心的距离,将其分配到距离最近的簇中。
步骤3:更新聚类中心
- 对每个簇,计算其所有数据点的平均值,并将聚类中心移动到该平均值的位置。
步骤4:迭代直至收敛
- 重复步骤2和步骤3,直至聚类中心不再发生明显变化或达到预定的迭代次数。这时算法被认为收敛。
1.3 算法的优势与局限性
优势:
- 简单易实现: K均值算法相对简单,易于理解和实现。
- 计算效率高: 算法的计算复杂度较低,适用于大规模数据集。
- 适用性广泛: 在数据聚类结构相对简单的情况下,K均值算法表现良好。
局限性:
- 对初始值敏感: 初始聚类中心的选择可能影响算法的收敛结果,不同初始值可能导致不同的聚类结果。
- 对异常值敏感: 算法容易受到异常值和噪声的影响,可能导致聚类结果失真。
- 需要预先确定簇的数量K: 在实际问题中,确定簇的数量K并非总是容易,且K值的选择对最终结果有较大影响。
2. K均值算法的实现步骤
K均值算法的实现步骤是理解该算法的关键。让我们深入研究每个步骤,从初始聚类中心的选择到最终的收敛。
2.1 初始聚类中心的选择方法
初始聚类中心的选择直接影响着K均值算法的收敛速度和聚类结果。两种常用的方法是:
2.1.1 随机选择初始中心点
最简单的方法是从数据集中随机选择K个数据点作为初始聚类中心。这种方法简单直观,但可能受到初始点选择的不确定性影响。
2.1.2 K均值++算法
K均值++算法通过一系列计算,选择离已选中聚类中心越远的点作为新的聚类中心,有效避免了随机选择带来的问题,提高了算法的稳定性。具体步骤包括:
- 从数据集中随机选择第一个中心点。
- 对于剩余的数据点,计算每个点到已选中中心点的距离,选择距离较远的点作为新的中心点。
- 重复上述步骤,直到选择出K个初始聚类中心。
2.2 数据点与聚类中心的距离计算
K均值算法的核心是通过计算数据点与聚类中心的距离,将数据点分配到最近的簇。两种常用的距离计算方法是:
2.2.1 欧氏距离计算
欧氏距离是最常用的距离计算方法,其计算公式为:
∑ i = 1 n ( x i − y i ) 2 \sqrt{\sum_{i=1}^{n} (x_i - y_i)^2} i=1∑n(xi−yi)2
其中 x i x_i xi 和 y i y_i yi 分别是两个数据点在第i个维度上的坐标。
2.2.2 曼哈顿距离计算
曼哈顿距离是另一种常见的距离计算方法,其计算公式为:
∑ i = 1 n ∣ x i − y i ∣ \sum_{i=1}^{n} |x_i - y_i| i=1∑n∣xi−yi∣
2.3 更新聚类中心
在K均值算法中,数据点被分配到簇后,需要更新每个簇的中心位置。更新的方法是取簇中所有点的均值作为新的聚类中心。具体步骤如下:
- 对于每个簇,计算该簇中所有数据点在每个维度上的均值,得到新的聚类中心。
2.4 重复迭代直至收敛
K均值算法是一个迭代算法,通过不断迭代更新聚类中心,直到满足停止条件。常见的停止条件有:
- 固定迭代次数。
- 聚类中心不再发生明显变化。
算法迭代的具体步骤如下:
- 初始化K个聚类中心。
- 将每个数据点分配到最近的聚类中心。
- 更新每个簇的聚类中心。
- 重复步骤2和3,直到满足停止条件。
这些实现步骤相互协作,确保了K均值算法的有效性和稳定性。在深入理解这些步骤后,我们将更好地掌握K均值算法的实际应用和调优技巧。
- K均值在Python中的应用
3.1 Python中的K均值算法库
在Python中,有着众多优秀的机器学习库,其中scikit-learn是应用最广泛的之一。其提供了丰富的聚类算法实现,包括了K均值算法。通过导入相应的模块,我们能够轻松地在Python中调用K均值算法的函数,实现高效的聚类。
3.2 数据准备与预处理
在应用K均值算法之前,我们需要对数据进行准备和预处理,确保数据的质量和一致性。这包括数据加载、清洗以及对特征的标准化。通过Python中的pandas和numpy库,我们能够方便地进行这些数据处理的步骤,为算法的输入做好充足的准备。
假设我们有以下的数据:
import pandas as pd# 示例数据集
data = {'Feature1': [1, 2, 2.5, 3, 6, 5, 4.5, 5.5],'Feature2': [2, 1.5, 2.8, 3.5, 4, 5, 4.5, 5]}df = pd.DataFrame(data)
在数据加载后,我们可以使用matplotlib
库进行简单的数据可视化,以更好地了解我们的数据分布:
import matplotlib.pyplot as pltplt.scatter(df['Feature1'], df['Feature2'])
plt.xlabel('Feature1')
plt.ylabel('Feature2')
plt.title('Data Distribution')
plt.show()
3.3 调用算法进行聚类
scikit-learn库提供了KMeans
类,通过实例化该类并调用相应的方法,我们能够在Python中轻松实现K均值算法的聚类。在这一步骤中,我们将介绍如何设置算法的参数,包括聚类数目K、初始化方法等,并展示如何通过fit方法对数据进行聚类。
下面是具体的实现代码:
from sklearn.cluster import KMeans
# 确定簇的数量为2
kmeans = KMeans(n_clusters=2)
# 进行训练
kmeans.fit(df)
# 在输入的数据集上增加对应的簇类别
labels = kmeans.labels_
df['Cluster'] = labels
KMeans函数详解:
KMeans
是 scikit-learn 库中实现K均值算法的类,用于进行聚类分析。以下是对 KMeans
常用参数的详细解释供参考,不同版本之间的默认值可能会有区别,这里给出一些供大家参考:
-
n_clusters(默认值:8):
- 用途:指定簇的数量,即K值。这是K均值算法中必须提供的参数。
-
init(默认值:‘k-means++’):
- 用途:确定初始簇中心的方法。
- 可选值:
- ‘k-means++’:使用智能初始化方法,尽量确保初始中心之间的距离较远,有助于算法收敛更快。
- ‘random’:随机选择数据中的点作为初始簇中心。
-
n_init(默认值:10):
- 用途:指定算法运行的次数,每次使用不同的初始簇中心,以避免陷入局部最小值。
- 对于给定的
n_clusters
值,选择具有最小惯性(簇内平方和)的运行结果。
-
max_iter(默认值:300):
- 用途:指定每次运行的最大迭代次数,控制算法的运行时间。
-
tol(默认值:1e-4):
- 用途:控制算法收敛的阈值,当两次迭代的中心之间的最大差异小于
tol
时,认为算法已经收敛。
- 用途:控制算法收敛的阈值,当两次迭代的中心之间的最大差异小于
-
algorithm(默认值:‘auto’):
- 用途:指定K均值算法的实现方式。
- 可选值:
- ‘auto’:根据数据的大小和类型自动选择适当的算法。
- ‘full’:使用经典的EM-style算法。
- ‘elkan’:更有效的K均值算法,适用于较大的数据集。
-
random_state(默认值:None):
- 用途:设置随机种子,确保每次运行得到的结果一致,便于复现实验。
-
n_jobs(默认值:None):
- 用途:指定并行运算的数量,加速运行。设置为 -1 表示使用所有可用的CPU核心。
-
precompute_distances(默认值:‘auto’):
- 用途:控制是否在算法运行前计算所有数据点之间的距离。
- 可选值:
- ‘auto’:根据数据大小自动判断是否计算距离。
- True:始终计算距离。
- False:不计算距离。
3.4 结果可视化与分析
聚类算法的结果可视化是理解算法效果的重要手段。通过使用Python中的matplotlib或seaborn等绘图库,我们能够将聚类结果以直观的图形呈现。除此之外,我们将深入分析聚类结果,探讨不同簇之间的特点,帮助读者更好地理解数据的结构。
通过可视化查看K均值算法的聚类结果:
plt.scatter(df['Feature1'], df['Feature2'], c=df['Cluster'], cmap='viridis')
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s=300, c='red', marker='X')
plt.xlabel('Feature1')
plt.ylabel('Feature2')
plt.title('K-Means Clustering Result')
plt.show()
我们使用散点图表示数据点,每个簇用不同的颜色标识,同时用红色的"X"表示聚类中心。这个可视化展示了K均值算法对数据的聚类效果。
4. K均值算法的参数调优与改进
4.1 如何选择合适的K值?
选择合适的K值对于K均值算法的成功应用至关重要。以下是两种常用的选择方法:
4.1.1 肘部法则(Elbow Method)
肘部法则是一种直观且常用的K值选择方法。其基本思想是随着聚类数K的增加,样本划分会更精细,每个簇的聚合度会逐渐提高,从而误差平方和(SSE)会逐渐减小。然而,当K达到真实聚类数时,增加K值所带来的聚合度提高会迅速减缓,形成一个肘部的拐点。该拐点对应的K值即为数据的真实聚类数。
下面是实现的python代码,供大家参考:
import os
os.environ['OMP_NUM_THREADS'] = '2'import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文显示的字体,SimHei 是宋体的黑体版本
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示为方块的问题# 构建模拟数据
data, _ = make_blobs(n_samples=300, centers=4, random_state=12)# 计算不同K值下的SSE
sse = []
k_range = range(1, 11)
for k in k_range:kmeans = KMeans(n_clusters=k, n_init=10, random_state=12)kmeans.fit(data)sse.append(kmeans.inertia_)# 绘制肘部法则图像
fig, ax = plt.subplots()
ax.plot(k_range, sse, marker='o')
ax.set_xlabel('K值')
ax.set_ylabel('误差平方和(SSE)')
ax.set_title('肘部法则示例')
plt.show()
运行上述代码后,结果如下:
从上图中,我们可以看出k为2或者3时,比较合适。
优化版本,自动判断:
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from kneed import KneeLocator# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文显示的字体,SimHei 是宋体的黑体版本
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示为方块的问题# 构建模拟数据
data, _ = make_blobs(n_samples=300, centers=4, random_state=12)# 计算不同K值下的SSE
sse = []
k_range = range(1, 11)
for k in k_range:kmeans = KMeans(n_clusters=k, n_init=10, random_state=12)kmeans.fit(data)sse.append(kmeans.inertia_)# 使用KneeLocator自动检测肘部
kl = KneeLocator(k_range, sse, curve="convex", direction="decreasing")
optimal_k = kl.elbow# 绘制肘部法则图像
fig, ax = plt.subplots()
ax.plot(k_range, sse, marker='o')
ax.set_xlabel('K值')
ax.set_ylabel('误差平方和(SSE)')
ax.set_title('自动检测肘部法则示例')# 标记自动检测得到的肘部位置
ax.vlines(optimal_k, plt.ylim()[0], plt.ylim()[1], linestyles='dashed', colors='red', label='自动检测肘部')plt.legend()
plt.show()# 打印自动检测得到的最优K值
print("自动检测得到的最优K值:", optimal_k)
运行上述代码后,结果如下:
4.1.2 轮廓系数法
轮廓系数是一种用于度量聚类效果的指标,其值在-1到1之间,数值越大表示聚类效果越好。具体计算步骤如下:
- 对于每个样本,计算它与同簇其他样本的平均距离,记作a(i)。
- 对于每个样本,计算它与最近异簇样本的平均距离,记作b(i)。
- 计算样本的轮廓系数:S(i) = (b(i) - a(i)) / max{a(i), b(i)}。
- 对所有样本的轮廓系数取平均得到整体聚类的轮廓系数。
在选择K值时,我们可以尝试不同的K值,计算其对应的轮廓系数,选择轮廓系数达到最大值的K值作为最优的聚类数。
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import silhouette_samples, silhouette_score# 构建模拟数据
data, _ = make_blobs(n_samples=300, centers=4, random_state=12)# 计算不同K值下的轮廓系数
silhouette_scores = []
k_range = range(2, 11) # K值至少为2
for k in k_range:kmeans = KMeans(n_clusters=k, n_init=10, random_state=12)labels = kmeans.fit_predict(data)silhouette_avg = silhouette_score(data, labels)silhouette_scores.append(silhouette_avg)# 绘制轮廓系数法图像
plt.plot(k_range, silhouette_scores, marker='o')
plt.xlabel('K值')
plt.ylabel('轮廓系数')
plt.title('轮廓系数法示例')
plt.show()
运行上述代码后,我们得到下面的输出:
从上图中,我们依然可以看出最佳k值为2
4.2 改进K均值算法的方法
在实际应用中,K均值算法可能受到一些限制,特别是对于不规则形状、密度差异较大的簇。为了克服这些限制,可以采用一些改进的方法,使算法更加鲁棒和适用于多样化的数据集。
4.2.1 基于密度的聚类
背景: K均值算法在处理具有不同密度簇时可能表现不佳,因为其对所有簇的权重都是相等的。
方法: 基于密度的聚类方法通过考虑数据点周围的密度来调整簇的形状。DBSCAN(Density-Based Spatial Clustering of Applications with Noise)是一种常用的基于密度的聚类算法,它能够发现任意形状的簇并鲁棒地处理噪声。
实例: 我们将演示如何使用DBSCAN算法改进K均值算法,以适应具有不同密度簇的情况。通过比较改进前后的聚类效果,读者将更好地理解这一改进方法的实际应用。
具体代码:
from sklearn.cluster import DBSCAN
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs# 创建具有不同密度簇的数据集
X, _ = make_blobs(n_samples=300, centers=3, cluster_std=[1.0, 2.5, 0.5], random_state=12)# 使用DBSCAN进行聚类
dbscan = DBSCAN(eps=0.5, min_samples=5)
labels = dbscan.fit_predict(X)# 可视化聚类结果
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', marker='o', edgecolor='black')
plt.title("基于密度的聚类 - 使用DBSCAN")
plt.show()
4.2.2 高斯混合模型
背景: K均值算法假设每个簇都是由一个球形的聚类中心表示,对于复杂形状的簇可能不够灵活。
方法: 高斯混合模型(Gaussian Mixture Model,GMM)是一种基于概率分布的聚类方法,它允许每个簇具有不同的形状和方向。每个簇被建模为一个概率分布的高斯分布。
实例: 我们将介绍如何使用GMM对K均值算法进行改进,以适应复杂形状的簇。通过在实际数据集上进行对比实验,展示GMM的优越性。
具体代码:
from sklearn.mixture import GaussianMixture
import numpy as np# 创建具有不同形状簇的数据集
X = np.concatenate([np.random.normal(0, 1, size=(100, 2)),np.random.normal(5, 1, size=(100, 2)),np.random.normal(10, 1, size=(100, 2))])# 使用GMM进行聚类
gmm = GaussianMixture(n_components=3, covariance_type='full', random_state=12)
labels = gmm.fit_predict(X)# 可视化聚类结果
plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', marker='o', edgecolor='black')
plt.title("高斯混合模型 - 使用GMM")
plt.show()
4.2.3 实际案例分析与效果评估
案例选择: 选择一个包含不规则形状、密度变化大的数据集,以展示K均值算法改进方法的实际效果。
评估指标: 使用聚类效果评估指标,比如轮廓系数、互信息等,来量化改进算法在真实数据上的表现。
from sklearn.metrics import silhouette_score
from sklearn.datasets import make_moons
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans# 创建月牙形数据集
X, _ = make_moons(n_samples=300, noise=0.05, random_state=12)# 使用K均值算法进行初始聚类
kmeans = KMeans(n_clusters=2, random_state=42)
initial_labels = kmeans.fit_predict(X)# 使用DBSCAN进行基于密度的聚类
dbscan = DBSCAN(eps=0.3, min_samples=5)
dbscan_labels = dbscan.fit_predict(X)# 计算轮廓系数
initial_score = silhouette_score(X, initial_labels)
dbscan_score = silhouette_score(X, dbscan_labels)print(f"K均值算法轮廓系数: {initial_score}")
print(f"DBSCAN轮廓系数: {dbscan_score}")
4.3 实际案例
背景描述:
我们选择一个具体的案例,即顾客购物行为分析。假设我们有一家零售商店,希望了解顾客的购物行为,以便更好地进行市场细分和商品定价。
实现代码:
import pandas as pd
import numpy as np# 生成1000个顾客ID
customer_ids = np.arange(1, 1001)# 生成购物金额和购物频率的随机数据
shopping_amounts = np.random.uniform(10, 200, 1000) # 购物金额在10到200之间
shopping_frequencies = np.random.uniform(1, 10, 1000) # 购物频率在1到10之间# 创建数据框
customer_data = pd.DataFrame({'CustomerID': customer_ids,'ShoppingAmount': shopping_amounts,'ShoppingFrequency': shopping_frequencies
})from sklearn.cluster import KMeans
import matplotlib.pyplot as plt# 提取用于聚类的特征
features = customer_data[['ShoppingAmount', 'ShoppingFrequency']]# 选择聚类数K为3
kmeans = KMeans(n_clusters=3)
customer_data['Cluster'] = kmeans.fit_predict(features)# 获取簇心坐标
cluster_centers = kmeans.cluster_centers_# 可视化聚类结果
plt.scatter(customer_data['ShoppingAmount'], customer_data['ShoppingFrequency'], c=customer_data['Cluster'], cmap='viridis')
plt.scatter(cluster_centers[:, 0], cluster_centers[:, 1], marker='X', s=200, c='red', label='簇心') # 添加簇心标记
plt.title('顾客购物行为聚类结果')
plt.xlabel('购物金额')
plt.ylabel('购物频率')
plt.legend()
plt.show()from sklearn.metrics import silhouette_score# 计算轮廓系数
silhouette_avg = silhouette_score(features, customer_data['Cluster'])
print(f"整体轮廓系数: {silhouette_avg}")
应用到实际业务中:
簇 | 市场细分 | 定价策略 | 促销活动 |
---|---|---|---|
1 | 低购物金额、低购物频率 | 推出价格亲民的商品,提高性价比 | 实施积分制度、首次购物折扣等促销,吸引频繁光顾 |
2 | 中等购物金额、高购物频率 | 提供多样化商品选择,注重实用性和新颖性 | 设计会员专享活动、积分兑换等奖励机制,提升客户忠诚度 |
13 | 高购物金额、低购物频率 | 提供高价值商品,确保品质 | 定期推出限时折扣、生日特权等高价值促销 |
写在最后
通过这篇博客,我们希望读者能够深入理解K均值算法,掌握其实现步骤,并在实际项目中灵活应用。聚类算法是数据科学领域中的一把利器,而K均值算法则是其中最亮眼的一颗星。愿您在学习的过程中有所收获,欢迎随时探讨与交流。