news 2026/4/21 18:03:25

K-means聚类实战:用Python给鸢尾花(Iris)数据集自动分个类

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
K-means聚类实战:用Python给鸢尾花(Iris)数据集自动分个类

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, columns=feature_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, i+1) plt.hist(X_scaled[:, i], bins=20) plt.title(feature_names[i]) plt.tight_layout() plt.show()

特征相关性分析:

import seaborn as sns corr_matrix = df.corr() sns.heatmap(corr_matrix, annot=True, cmap='coolwarm') 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_clusters=k, random_state=42) 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()

分析结果:

  • 肘部法则建议K=3(与实际品种数一致)
  • 轮廓系数在K=3时达到峰值
  • 最终选择K=3进行建模

4. 构建K-means模型与结果分析

训练最终模型并分析结果:

# 训练K-means模型 kmeans = KMeans(n_clusters=3, random_state=42) clusters = kmeans.fit_predict(X_scaled) # 将聚类结果与真实标签对比 results = pd.DataFrame({ '真实品种': y, '预测聚类': clusters, '品种名称': target_names[y] }) print(results.groupby(['真实品种', '预测聚类']).size().unstack())

输出混淆矩阵:

真实\预测012
setosa5000
versicolor0473
virginica01436

可视化聚类结果:

from sklearn.decomposition import PCA # 使用PCA降维到2D便于可视化 pca = PCA(n_components=2) 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], c=y, cmap='viridis') plt.title('真实品种分布') plt.colorbar(ticks=[0, 1, 2], label='品种') plt.subplot(1, 2, 2) plt.scatter(X_pca[:, 0], X_pca[:, 1], c=clusters, cmap='viridis') plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], s=200, marker='X', c='red') 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.751

5. 模型优化与高级技巧

提升K-means性能的几种实用方法:

  1. 特征选择优化
# 只使用花瓣特征 X_petal = X[:, 2:4] kmeans_petal = KMeans(n_clusters=3, random_state=42).fit(X_petal) print(f"仅用花瓣特征的调整兰德指数: {adjusted_rand_score(y, kmeans_petal.labels_):.3f}")
  1. 初始化方法改进
# 使用k-means++初始化 kmeans_plus = KMeans(n_clusters=3, init='k-means++', random_state=42).fit(X_scaled) print(f"k-means++初始化的调整兰德指数: {adjusted_rand_score(y, kmeans_plus.labels_):.3f}")
  1. 多次运行取最优
best_score = -1 for _ in range(10): kmeans = KMeans(n_clusters=3, random_state=None).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}")
  1. 不同距离度量尝试
from sklearn.metrics import pairwise_distances # 自定义距离函数 def manhattan_distance(x, y): return np.sum(np.abs(x - y)) # 使用预计算距离矩阵 dist_matrix = pairwise_distances(X_scaled, metric=manhattan_distance) kmeans_manhattan = KMeans(n_clusters=3, random_state=42, init='k-means++', n_init=1, precompute_distances=True).fit(dist_matrix)

6. 业务解读与决策建议

基于聚类结果的实用洞察:

  1. 品种区分度分析

    • setosa品种完全被正确分类(簇0)
    • versicolor和virginica存在部分重叠(簇1和簇2)
  2. 特征重要性排序

# 计算每个特征对聚类的贡献度 feature_importance = np.std(kmeans.cluster_centers_, axis=0) plt.barh(feature_names, feature_importance) plt.title('特征对聚类的贡献度') plt.show()
  1. 异常点检测
# 计算每个样本到其簇中心的距离 distances = np.min(kmeans.transform(X_scaled), axis=1) outliers = np.where(distances > np.percentile(distances, 95))[0] print(f"检测到的潜在异常样本索引: {outliers}")

实际应用建议:

  • 对于园艺分类,可优先关注花瓣特征
  • 在质量检测中,距离簇中心过远的样本可能需要人工复核
  • 当引入新品种时,需要重新评估K值选择
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/21 17:58:51

STM32 ADC实战:土壤湿度传感器数据采集与校准全解析

1. 土壤湿度传感器与STM32 ADC基础认知 第一次接触土壤湿度传感器时,我把它插进花盆里,发现数值乱跳得像心电图。后来才明白,这背后是模拟信号到数字世界的奇妙旅程。常见的三线制传感器(VCC、GND、AO)工作时&#xf…

作者头像 李华
网站建设 2026/4/21 17:57:41

别再乱用connect了!Qt信号槽传参的四种实战姿势(附代码避坑)

Qt信号槽传参的四种高阶用法与避坑指南 在开发复杂Qt桌面应用时,对象间的通信往往需要传递各种参数。看似简单的connect操作,实则暗藏玄机。我曾在一个多控件编辑器项目中,因为信号槽传参不当导致内存泄漏和性能问题,调试了整整三…

作者头像 李华