当前位置: 首页 > news >正文

机器学习-K-means聚类算法

# K-means聚类算法

## 前言

聚类分析是机器学习中无监督学习的重要分支,而K-means算法作为最经典和广泛使用的聚类算法之一,在数据挖掘、图像分割、客户分群等领域有着重要应用。本文将深入探讨K-means算法的原理、实现方法、评估指标以及实际应用案例。

## 1. K-means算法概述

### 1.1 什么是K-means聚类

K-means聚类是一种基于距离的聚类算法,其目标是将n个数据点划分为k个簇,使得每个数据点都属于距离其最近的簇中心所在的簇。算法通过迭代优化来最小化簇内平方和(Within-Cluster Sum of Squares, WCSS)。

### 1.2 算法核心思想

K-means算法的核心思想是:
1. **初始化**:随机选择k个初始聚类中心
2. **分配**:将每个数据点分配到最近的聚类中心
3. **更新**:重新计算每个簇的中心点
4. **迭代**:重复步骤2和3,直到收敛

### 1.3 算法优缺点

**优点:**
- 算法简单,易于理解和实现
- 计算复杂度相对较低
- 适用于球形簇的聚类
- 可扩展性好

**缺点:**
- 需要预先指定聚类数量k
- 对初始聚类中心敏感
- 对异常值敏感
- 假设簇是球形的,对非球形簇效果不佳

## 2. K-means算法实现

### 2.1 基础实现

```python
import os
import matplotlib
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.metrics import calinski_harabasz_score

# 设置环境变量
os.environ['OMP_NUM_THREADS'] = '4'
matplotlib.use('TkAgg')

def basic_kmeans_demo():
"""K-means基础演示"""
# 1. 生成模拟数据
x, y = make_blobs(
n_samples=1000,
n_features=2,
centers=[[-1, -1], [0, 0], [1, 1], [2, 2]],
cluster_std=[0.4, 0.2, 0.2, 0.2],
random_state=23
)

# 2. 可视化原始数据
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
plt.scatter(x[:, 0], x[:, 1], c='blue', alpha=0.6)
plt.title('原始数据分布')
plt.xlabel('特征1')
plt.ylabel('特征2')

# 3. K-means聚类
kmeans = KMeans(n_clusters=4, random_state=23)
y_pred = kmeans.fit_predict(x)

# 4. 可视化聚类结果
plt.subplot(1, 2, 2)
plt.scatter(x[:, 0], x[:, 1], c=y_pred, cmap='viridis', alpha=0.6)
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], 
c='red', marker='x', s=200, linewidths=3)
plt.title('K-means聚类结果')
plt.xlabel('特征1')
plt.ylabel('特征2')

plt.tight_layout()
plt.show()

# 5. 评估聚类效果
ch_score = calinski_harabasz_score(x, y_pred)
print(f"Calinski-Harabasz指数: {ch_score:.2f}")

return kmeans, y_pred
```

### 2.2 最优K值选择

选择合适的K值是K-means算法的关键问题。常用的方法包括肘部法则、轮廓系数和Calinski-Harabasz指数。

```python
from sklearn.metrics import silhouette_score, calinski_harabasz_score

def find_optimal_k():
"""寻找最优K值"""
# 生成数据
x, y = make_blobs(
n_samples=1000,
n_features=2,
centers=[[-1, -1], [0, 0], [1, 1], [2, 2]],
cluster_std=[0.4, 0.2, 0.2, 0.2],
random_state=23
)

# 存储不同K值的评估指标
sse_list = []  # 簇内平方和
sc_list = []   # 轮廓系数
ch_list = []   # Calinski-Harabasz指数

k_range = range(2, 20)

for k in k_range:
kmeans = KMeans(n_clusters=k, max_iter=100, random_state=23)
kmeans.fit(x)
y_pred = kmeans.predict(x)

# 计算评估指标
sse_list.append(kmeans.inertia_)  # 簇内平方和
sc_list.append(silhouette_score(x, y_pred))  # 轮廓系数
ch_list.append(calinski_harabasz_score(x, y_pred))  # CH指数

# 可视化评估指标
plt.figure(figsize=(15, 5))

# 肘部法则
plt.subplot(1, 3, 1)
plt.plot(k_range, sse_list, 'bo-')
plt.xlabel('K值')
plt.ylabel('簇内平方和(SSE)')
plt.title('肘部法则')
plt.grid(True)

# 轮廓系数
plt.subplot(1, 3, 2)
plt.plot(k_range, sc_list, 'ro-')
plt.xlabel('K值')
plt.ylabel('轮廓系数')
plt.title('轮廓系数法')
plt.grid(True)

# Calinski-Harabasz指数
plt.subplot(1, 3, 3)
plt.plot(k_range, ch_list, 'go-')
plt.xlabel('K值')
plt.ylabel('CH指数')
plt.title('Calinski-Harabasz指数')
plt.grid(True)

plt.tight_layout()
plt.show()

# 输出最优K值
optimal_k_sc = k_range[sc_list.index(max(sc_list))]
optimal_k_ch = k_range[ch_list.index(max(ch_list))]

print(f"轮廓系数法推荐K值: {optimal_k_sc}")
print(f"CH指数法推荐K值: {optimal_k_ch}")

return optimal_k_sc, optimal_k_ch
```

## 3. 聚类评估方法详解

### 3.1 内部评估指标

#### 3.1.1 簇内平方和(SSE/Inertia)
```python
def calculate_sse(x, y_pred, centers):
"""计算簇内平方和"""
sse = 0
for i in range(len(centers)):
cluster_points = x[y_pred == i]
if len(cluster_points) > 0:
sse += np.sum((cluster_points - centers[i]) ** 2)
return sse
```

#### 3.1.2 轮廓系数(Silhouette Score)
轮廓系数衡量一个样本与其自身簇的相似度相对于其他簇的相似度。

```python
def silhouette_analysis():
"""轮廓系数分析"""
x, y = make_blobs(n_samples=1000, n_features=2, centers=4, random_state=23)

# 不同K值的轮廓系数
k_values = [2, 3, 4, 5, 6]
silhouette_scores = []

for k in k_values:
kmeans = KMeans(n_clusters=k, random_state=23)
y_pred = kmeans.fit_predict(x)
score = silhouette_score(x, y_pred)
silhouette_scores.append(score)
print(f"K={k}, 轮廓系数: {score:.3f}")

return silhouette_scores
```

#### 3.1.3 Calinski-Harabasz指数
CH指数基于簇间和簇内的方差比,值越大表示聚类效果越好。

```python
def ch_analysis():
"""Calinski-Harabasz指数分析"""
x, y = make_blobs(n_samples=1000, n_features=2, centers=4, random_state=23)

k_values = range(2, 10)
ch_scores = []

for k in k_values:
kmeans = KMeans(n_clusters=k, random_state=23)
y_pred = kmeans.fit_predict(x)
score = calinski_harabasz_score(x, y_pred)
ch_scores.append(score)
print(f"K={k}, CH指数: {score:.2f}")

return ch_scores
```

### 3.2 外部评估指标

当有真实标签时,可以使用外部评估指标:

```python
from sklearn.metrics import adjusted_rand_score, normalized_mutual_info_score

def external_evaluation():
"""外部评估指标"""
x, y_true = make_blobs(n_samples=1000, n_features=2, centers=4, random_state=23)

kmeans = KMeans(n_clusters=4, random_state=23)
y_pred = kmeans.fit_predict(x)

# 调整兰德指数
ari = adjusted_rand_score(y_true, y_pred)
print(f"调整兰德指数: {ari:.3f}")

# 标准化互信息
nmi = normalized_mutual_info_score(y_true, y_pred)
print(f"标准化互信息: {nmi:.3f}")

return ari, nmi
```

## 4. 实际应用案例:客户分群

### 4.1 客户分群业务背景

在电商和零售行业中,客户分群是重要的营销策略。通过分析客户的消费行为、收入水平等特征,可以将客户分为不同的群体,从而制定个性化的营销策略。

### 4.2 数据准备与预处理

```python
import pandas as pd

def customer_segmentation():
"""客户分群案例"""
# 1. 加载客户数据
df = pd.read_csv("customers.csv")
print("数据基本信息:")
print(df.info())
print("\n数据预览:")
print(df.head())

# 2. 特征选择
# 假设使用年收入和消费分数作为聚类特征
x = df.iloc[:, 3:5]  # 选择第4和第5列作为特征
print(f"\n特征数据形状: {x.shape}")
print("特征数据预览:")
print(x.head())

return x, df
```

### 4.3 寻找最优K值

```python
def find_optimal_k_customers(x):
"""为客户数据寻找最优K值"""
sse_list = []
sc_list = []

k_range = range(2, 20)

for k in k_range:
kmeans = KMeans(n_clusters=k, max_iter=100, random_state=23)
kmeans.fit(x)
y_pred = kmeans.predict(x)

sse_list.append(kmeans.inertia_)
sc_list.append(silhouette_score(x, y_pred))

# 可视化
plt.figure(figsize=(15, 5))

plt.subplot(1, 2, 1)
plt.plot(k_range, sse_list, 'bo-')
plt.xlabel('K值')
plt.ylabel('簇内平方和(SSE)')
plt.title('肘部法则 - 客户分群')
plt.grid(True)

plt.subplot(1, 2, 2)
plt.plot(k_range, sc_list, 'ro-')
plt.xlabel('K值')
plt.ylabel('轮廓系数')
plt.title('轮廓系数法 - 客户分群')
plt.grid(True)

plt.tight_layout()
plt.show()

# 选择最优K值
optimal_k = k_range[sc_list.index(max(sc_list))]
print(f"推荐K值: {optimal_k}")

return optimal_k
```

### 4.4 客户分群实现

```python
def perform_customer_clustering(x, optimal_k):
"""执行客户分群"""
# 1. 训练K-means模型
kmeans = KMeans(n_clusters=optimal_k, max_iter=100, random_state=23)
kmeans.fit(x)

# 2. 预测客户类别
y_pred = kmeans.predict(x)

# 3. 可视化分群结果
plt.figure(figsize=(10, 8))
colors = ['red', 'blue', 'green', 'orange', 'purple', 'brown', 'pink', 'gray']

for i in range(optimal_k):
cluster_data = x.values[y_pred == i]
plt.scatter(cluster_data[:, 0], cluster_data[:, 1], 
c=colors[i % len(colors)], label=f'客户群体 {i+1}', alpha=0.7)

# 绘制聚类中心
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:, 1], 
c='black', marker='x', s=200, linewidths=3, label='聚类中心')

plt.xlabel('年收入')
plt.ylabel('消费分数')
plt.title(f'客户分群结果 (K={optimal_k})')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()

# 4. 分析各客户群体特征
print("\n各客户群体特征分析:")
for i in range(optimal_k):
cluster_data = x.values[y_pred == i]
print(f"\n客户群体 {i+1}:")
print(f"  客户数量: {len(cluster_data)}")
print(f"  平均年收入: {cluster_data[:, 0].mean():.2f}")
print(f"  平均消费分数: {cluster_data[:, 1].mean():.2f}")

return kmeans, y_pred
```

### 4.5 客户群体分析

```python
def analyze_customer_segments(df, y_pred, optimal_k):
"""分析客户群体特征"""
# 添加聚类标签到原始数据
df['Cluster'] = y_pred

print("客户群体详细分析:")
print("=" * 50)

for i in range(optimal_k):
cluster_data = df[df['Cluster'] == i]
print(f"\n客户群体 {i+1} (共{len(cluster_data)}人):")
print("-" * 30)

# 基本统计信息
if 'Age' in df.columns:
print(f"平均年龄: {cluster_data['Age'].mean():.1f}岁")
if 'Annual Income (k$)' in df.columns:
print(f"平均年收入: {cluster_data['Annual Income (k$)'].mean():.1f}k$")
if 'Spending Score (1-100)' in df.columns:
print(f"平均消费分数: {cluster_data['Spending Score (1-100)'].mean():.1f}")

# 性别分布
if 'Gender' in df.columns:
gender_dist = cluster_data['Gender'].value_counts()
print(f"性别分布: {dict(gender_dist)}")

return df
```

## 5. 高级应用:XGBoost与聚类结合

### 5.1 红酒品质多分类案例

```python
import xgboost as xgb
import joblib
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import classification_report, accuracy_score
from sklearn.model_selection import StratifiedKFold
from sklearn.utils import class_weight
from collections import Counter

def wine_quality_classification():
"""红酒品质多分类案例"""

def data_split():
"""数据分割"""
df = pd.read_csv("红酒品质分类.csv")
x = df.iloc[:, :-1]
y = df.iloc[:, -1] - 3  # 将标签从3-8转换为0-5

print(f"标签分布: {Counter(y)}")

# 分层采样分割数据
x_train, x_test, y_train, y_test = train_test_split(
x, y, test_size=0.2, random_state=23, stratify=y
)

# 保存数据
pd.concat([x_train, y_train], axis=1).to_csv(
"红酒品质分类_train.csv", index=False
)
pd.concat([x_test, y_test], axis=1).to_csv(
"红酒品质分类_test.csv", index=False
)

return x_train, x_test, y_train, y_test

def train_model():
"""训练模型"""
# 加载数据
train_data = pd.read_csv("红酒品质分类_train.csv")
test_data = pd.read_csv("红酒品质分类_test.csv")

x_train = train_data.iloc[:, :-1]
y_train = train_data.iloc[:, -1]
x_test = test_data.iloc[:, :-1]
y_test = test_data.iloc[:, -1]

# 创建XGBoost模型
model = xgb.XGBClassifier(
max_depth=5,
n_estimators=100,
learning_rate=0.1,
random_state=24,
objective='multi:softmax'
)

# 处理样本不平衡
sample_weights = class_weight.compute_sample_weight("balanced", y_train)

# 训练模型
model.fit(x_train, y_train, sample_weight=sample_weights)

# 评估模型
y_pred = model.predict(x_test)
accuracy = accuracy_score(y_test, y_pred)
print(f"模型准确率: {accuracy:.4f}")

# 保存模型
joblib.dump(model, "红酒品质分类.pkl")
print("模型保存成功")

return model, accuracy

def hyperparameter_tuning():
"""超参数调优"""
train_data = pd.read_csv("红酒品质分类_train.csv")
test_data = pd.read_csv("红酒品质分类_test.csv")

x_train = train_data.iloc[:, :-1]
y_train = train_data.iloc[:, -1]
x_test = test_data.iloc[:, :-1]
y_test = test_data.iloc[:, -1]

# 参数网格
param_grid = {
'max_depth': [3, 5, 8, 10, 12],
'n_estimators': [100, 130, 150, 180, 230],
'learning_rate': [0.1, 0.3, 0.5, 1.0, 1.2]
}

# 分层K折交叉验证
skf = StratifiedKFold(n_splits=2, shuffle=True, random_state=23)

# 网格搜索
model = xgb.XGBClassifier()
grid_search = GridSearchCV(model, param_grid, cv=skf)
grid_search.fit(x_train, y_train)

# 评估最佳模型
y_pred = grid_search.predict(x_test)
accuracy = accuracy_score(y_test, y_pred)

print(f"网格搜索最佳参数: {grid_search.best_params_}")
print(f"网格搜索最佳分数: {grid_search.best_score_:.4f}")
print(f"测试集准确率: {accuracy:.4f}")

return grid_search

# 执行完整流程
print("1. 数据分割")
data_split()

print("\n2. 模型训练")
train_model()

print("\n3. 超参数调优")
hyperparameter_tuning()
```

## 6. K-means算法优化策略

### 6.1 初始化优化

```python
def kmeans_plus_plus_init(x, k):
"""K-means++初始化"""
centers = []
centers.append(x[np.random.randint(x.shape[0])])

for _ in range(k - 1):
distances = []
for point in x:
min_dist = min([np.linalg.norm(point - center) for center in centers])
distances.append(min_dist ** 2)

probabilities = distances / np.sum(distances)
cumulative_probabilities = np.cumsum(probabilities)
r = np.random.random()

for i, prob in enumerate(cumulative_probabilities):
if r < prob:
centers.append(x[i])
break

return np.array(centers)
```

### 6.2 处理不同形状的簇

```python
from sklearn.cluster import DBSCAN, AgglomerativeClustering

def alternative_clustering_methods(x):
"""替代聚类方法"""

# DBSCAN - 基于密度的聚类
dbscan = DBSCAN(eps=0.5, min_samples=5)
y_dbscan = dbscan.fit_predict(x)

# 层次聚类
hierarchical = AgglomerativeClustering(n_clusters=4)
y_hierarchical = hierarchical.fit_predict(x)

# 可视化比较
plt.figure(figsize=(15, 5))

plt.subplot(1, 3, 1)
plt.scatter(x[:, 0], x[:, 1], c=y_dbscan, cmap='viridis')
plt.title('DBSCAN聚类')

plt.subplot(1, 3, 2)
plt.scatter(x[:, 0], x[:, 1], c=y_hierarchical, cmap='viridis')
plt.title('层次聚类')

plt.subplot(1, 3, 3)
kmeans = KMeans(n_clusters=4, random_state=23)
y_kmeans = kmeans.fit_predict(x)
plt.scatter(x[:, 0], x[:, 1], c=y_kmeans, cmap='viridis')
plt.title('K-means聚类')

plt.tight_layout()
plt.show()

return y_dbscan, y_hierarchical, y_kmeans
```

## 7. 实际应用建议

### 7.1 数据预处理

1. **标准化处理**:确保不同特征的量纲一致
2. **异常值处理**:K-means对异常值敏感,需要预处理
3. **特征选择**:选择与业务目标相关的特征

### 7.2 参数调优

1. **K值选择**:结合业务需求和统计指标
2. **初始化策略**:使用K-means++减少随机性
3. **迭代次数**:设置合理的最大迭代次数

### 7.3 结果解释

1. **业务含义**:为每个簇赋予业务含义
2. **特征分析**:分析各簇的特征分布
3. **应用策略**:制定针对性的应用策略

## 8. 总结

K-means聚类算法作为最经典的聚类算法之一,具有以下特点:

**优势:**
- 算法简单,易于理解和实现
- 计算效率高,适合大规模数据
- 在球形簇上表现良好
- 可解释性强

**局限性:**
- 需要预先指定聚类数量
- 对初始值敏感
- 假设簇是球形的
- 对异常值敏感

**应用场景:**
- 客户分群和用户画像
- 图像分割
- 数据压缩
- 异常检测

在实际应用中,需要根据数据特点和业务需求选择合适的聚类算法,并通过多种评估指标来验证聚类效果。同时,结合业务知识对聚类结果进行解释和应用,才能真正发挥聚类分析的价值。

## 9. 扩展阅读

- [Scikit-learn聚类算法官方文档](https://scikit-learn.org/stable/modules/clustering.html)
- 《数据挖掘:概念与技术》- Jiawei Han
- 《机器学习》- 周志华

---

*本文更新日期:2025年9月8日

*本文基于实际项目代码编写,所有代码均经过测试验证。如有问题,欢迎交流讨论。*


文章转载自:

http://FwqsrJDG.dyght.cn
http://50pLCFVD.dyght.cn
http://ngICS6dy.dyght.cn
http://G5PkgfWA.dyght.cn
http://ERxhs6q8.dyght.cn
http://oHy1P3iH.dyght.cn
http://zwmKs0VJ.dyght.cn
http://CQ90Tb6K.dyght.cn
http://AKDTDbPx.dyght.cn
http://O0ncz9HY.dyght.cn
http://Aootaksk.dyght.cn
http://crWeXxsB.dyght.cn
http://zY7CNeQn.dyght.cn
http://7lkwXV0N.dyght.cn
http://1CzZAcm7.dyght.cn
http://DloZlioe.dyght.cn
http://cmw3mL1f.dyght.cn
http://hHsfcLNT.dyght.cn
http://LU3sTN72.dyght.cn
http://2QDpwBjQ.dyght.cn
http://bYcolIgU.dyght.cn
http://0xXF8fKK.dyght.cn
http://9cgzh0bu.dyght.cn
http://WIagNE96.dyght.cn
http://RmTTrQ09.dyght.cn
http://HIdjPA55.dyght.cn
http://GBoo6MdF.dyght.cn
http://ZW2qMDOQ.dyght.cn
http://rTI7jPj5.dyght.cn
http://mmzmkO0D.dyght.cn
http://www.dtcms.com/a/373929.html

相关文章:

  • Java基础知识点汇总(六)
  • 鸿蒙:深色模式适配和浅色模式的切换
  • 房屋安全鉴定机构推荐名单
  • 各种协议 RDP、SSH、TELNET、VNC、X11、SFTP、FTP、Rlogin 的区别
  • 机器人控制知识点(一):机器人控制中的位置环增益 $K_p$ 是什么?
  • 米勒平台开通和关断过程分析
  • 【ComfyUI】混元3D 2.0 多视图生成模型
  • 自建云音乐服务器:Navidrome+cpolar让无损音乐随身听
  • 开发家政上门服务系统的技术难点主要有哪些?
  • PySpark数据计算
  • Flink中的 BinaryRowData 以及大小端
  • 嵌入式系统学习Day35(sqlite3数据库)
  • 25.9.8 C++day8作业
  • PySpark数据输入
  • C++工程实战入门笔记13-多态
  • Python元组:不可变但灵活的数据容器
  • 设计模式(策略,观察者,单例,工厂方法)
  • C++智能指针(先行版)
  • 安卓蓝牙文件传输完整指南
  • C++读文件(大学考试难度)
  • 拆解LinuxI2C驱动之mpu6050
  • Linux--线程
  • 中大型水闸安全监测的关键环节与措施
  • 基于QMkae/CMake配置QT生成的exe图标
  • 安科瑞电动机保护器:赋能化工冶炼行业高效安全生产的智能守护
  • 数据结构之链表(单向链表与双向链表)
  • 学习嵌入式的第三十五天——数据库
  • Coze源码分析-资源库-删除插件-后端源码-错误处理与总结
  • 中级统计师-统计法规-第一章 基本统计法律规范
  • 从日志到防火墙——一次“SQL注入”排查笔记