K-means聚类实战用Python给鸢尾花(Iris)数据集自动分个类鸢尾花数据集是机器学习领域的经典入门案例包含150个样本每个样本有4个特征萼片长度、萼片宽度、花瓣长度、花瓣宽度和对应的品种标签。我们将使用K-means这一无监督学习算法仅基于花的特征自动将其分成若干类别并与真实品种进行对比分析。1. 环境准备与数据探索首先导入必要的Python库并加载数据import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.datasets import load_iris from sklearn.preprocessing import StandardScaler # 加载数据集 iris load_iris() X iris.data y iris.target feature_names iris.feature_names target_names iris.target_names查看数据的基本统计信息df pd.DataFrame(X, columnsfeature_names) print(df.describe())输出结果将显示四个特征的统计量特征均值标准差最小值25%分位中位数75%分位最大值萼片长度5.840.834.305.105.806.407.90萼片宽度3.060.442.002.803.003.304.40花瓣长度3.761.771.001.604.355.106.90花瓣宽度1.200.760.100.301.301.802.50注意不同特征的数值范围差异较大建议进行标准化处理以提高聚类效果。2. 数据预处理与特征工程良好的数据预处理能显著提升聚类效果# 特征标准化 scaler StandardScaler() X_scaled scaler.fit_transform(X) # 可视化特征分布 plt.figure(figsize(12, 6)) for i in range(4): plt.subplot(2, 2, i1) plt.hist(X_scaled[:, i], bins20) plt.title(feature_names[i]) plt.tight_layout() plt.show()特征相关性分析import seaborn as sns corr_matrix df.corr() sns.heatmap(corr_matrix, annotTrue, cmapcoolwarm) plt.title(特征相关性矩阵) plt.show()关键发现花瓣长度与花瓣宽度高度相关0.96萼片宽度与其他特征相关性较弱考虑使用PCA降维可能有助于可视化3. 确定最佳聚类数量K-means需要预先指定聚类数量K我们使用肘部法则和轮廓系数来确定最佳K值from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score # 尝试不同的K值 inertia [] silhouette_scores [] K_range range(2, 8) for k in K_range: kmeans KMeans(n_clustersk, random_state42) kmeans.fit(X_scaled) inertia.append(kmeans.inertia_) silhouette_scores.append(silhouette_score(X_scaled, kmeans.labels_)) # 绘制肘部法则图 plt.figure(figsize(12, 5)) plt.subplot(1, 2, 1) plt.plot(K_range, inertia, bo-) plt.xlabel(K值) plt.ylabel(簇内平方和(Inertia)) plt.title(肘部法则) plt.subplot(1, 2, 2) plt.plot(K_range, silhouette_scores, ro-) plt.xlabel(K值) plt.ylabel(轮廓系数) plt.title(轮廓系数分析) plt.tight_layout() plt.show()分析结果肘部法则建议K3与实际品种数一致轮廓系数在K3时达到峰值最终选择K3进行建模4. 构建K-means模型与结果分析训练最终模型并分析结果# 训练K-means模型 kmeans KMeans(n_clusters3, random_state42) clusters kmeans.fit_predict(X_scaled) # 将聚类结果与真实标签对比 results pd.DataFrame({ 真实品种: y, 预测聚类: clusters, 品种名称: target_names[y] }) print(results.groupby([真实品种, 预测聚类]).size().unstack())输出混淆矩阵真实\预测012setosa5000versicolor0473virginica01436可视化聚类结果from sklearn.decomposition import PCA # 使用PCA降维到2D便于可视化 pca PCA(n_components2) X_pca pca.fit_transform(X_scaled) plt.figure(figsize(12, 6)) plt.subplot(1, 2, 1) plt.scatter(X_pca[:, 0], X_pca[:, 1], cy, cmapviridis) plt.title(真实品种分布) plt.colorbar(ticks[0, 1, 2], label品种) plt.subplot(1, 2, 2) plt.scatter(X_pca[:, 0], X_pca[:, 1], cclusters, cmapviridis) plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s200, markerX, cred) plt.title(K-means聚类结果) plt.colorbar(ticks[0, 1, 2], label聚类) plt.tight_layout() plt.show()模型评估指标from sklearn.metrics import adjusted_rand_score, homogeneity_score print(f调整兰德指数: {adjusted_rand_score(y, clusters):.3f}) print(f同质性分数: {homogeneity_score(y, clusters):.3f})典型输出结果调整兰德指数: 0.730同质性分数: 0.7515. 模型优化与高级技巧提升K-means性能的几种实用方法特征选择优化# 只使用花瓣特征 X_petal X[:, 2:4] kmeans_petal KMeans(n_clusters3, random_state42).fit(X_petal) print(f仅用花瓣特征的调整兰德指数: {adjusted_rand_score(y, kmeans_petal.labels_):.3f})初始化方法改进# 使用k-means初始化 kmeans_plus KMeans(n_clusters3, initk-means, random_state42).fit(X_scaled) print(fk-means初始化的调整兰德指数: {adjusted_rand_score(y, kmeans_plus.labels_):.3f})多次运行取最优best_score -1 for _ in range(10): kmeans KMeans(n_clusters3, random_stateNone).fit(X_scaled) current_score adjusted_rand_score(y, kmeans.labels_) if current_score best_score: best_score current_score print(f多次运行最佳调整兰德指数: {best_score:.3f})不同距离度量尝试from sklearn.metrics import pairwise_distances # 自定义距离函数 def manhattan_distance(x, y): return np.sum(np.abs(x - y)) # 使用预计算距离矩阵 dist_matrix pairwise_distances(X_scaled, metricmanhattan_distance) kmeans_manhattan KMeans(n_clusters3, random_state42, initk-means, n_init1, precompute_distancesTrue).fit(dist_matrix)6. 业务解读与决策建议基于聚类结果的实用洞察品种区分度分析setosa品种完全被正确分类簇0versicolor和virginica存在部分重叠簇1和簇2特征重要性排序# 计算每个特征对聚类的贡献度 feature_importance np.std(kmeans.cluster_centers_, axis0) plt.barh(feature_names, feature_importance) plt.title(特征对聚类的贡献度) plt.show()异常点检测# 计算每个样本到其簇中心的距离 distances np.min(kmeans.transform(X_scaled), axis1) outliers np.where(distances np.percentile(distances, 95))[0] print(f检测到的潜在异常样本索引: {outliers})实际应用建议对于园艺分类可优先关注花瓣特征在质量检测中距离簇中心过远的样本可能需要人工复核当引入新品种时需要重新评估K值选择