算法入门(九)—— 无监督学习介绍与K-Means实战(内附Kaggle实战源码与数据集)
监督学习到这里就算是结束了,接下来我们一起来看你一下无监督学习,无监督学习是机器学习中的一个重要分支,但它看起来有点“神秘”——你会发现,数据集里并没有告诉你哪个是对的答案,也没有提供标签告诉你什么是正解。那么,问题来了:我们到底在做什么呢?别急,今天就带你一起揭开这个“神秘面纱”。
1. 无监督学习的定义与特点
无监督学习(Unsupervised Learning)顾名思义,它与“监督”相反。监督学习中,我们知道输入和输出的关系(即数据集有标签),而无监督学习则没有这些标签。我们没有直接的指导信息,数据就像一个迷宫,我们需要自己去探索和发现其中的规律和结构。
无监督学习的核心任务:
- 数据结构发现:找出数据之间的隐藏关系和内在结构。
- 模式识别:从无标签的数据中挖掘出数据的共性和趋势。
举个例子,如果你有一堆新闻文章,标签没有给你“政治”“科技”“娱乐”等类别,那你就得通过算法来判断哪些文章相似、哪些文章可能属于同一个类别。
无监督学习的典型应用:
- 数据聚类:将数据分成若干个组(或簇),使得同一组内的数据相似度较高,不同组之间差异较大。
- 降维与特征提取:在数据维度很高的情况下,通过降维技术将数据压缩成更易于处理的形式,同时保留重要的特征信息。
- 异常检测:识别出与大多数数据行为不同的数据点,它们可能是异常点或异常行为。
2.聚类分析:数据的“分组游戏”
如果我们要给没有标签的动物们分组,无监督学习会要求我们找到数据中“相似”的动物并把它们放进同一组。那么,如何判断哪些动物应该在一起呢?这就是聚类分析的作用——根据数据的相似性来自动将数据分为不同的“簇”。
聚类算法介绍
聚类算法是无监督学习中最常用的技术之一,它的目的是将数据集分成若干个簇,使得同一簇中的数据相似度较高,而不同簇之间的差异较大。常见的聚类算法包括:
- K-means聚类:通过给定簇数K,迭代地调整簇的中心,使得数据点尽量与簇的中心点距离最小。经典且高效。
- 层次聚类:不需要预先指定簇数,通过计算所有数据点之间的距离来递归地合并或分割簇。
- DBSCAN(密度聚类):基于数据点的密度来形成簇,能够识别不规则形状的簇。
今天我们主要介绍最简单、最常用的K-means聚类。
接下来,让我们用一个Kaggle数据集来演示如何进行聚类分析,具体使用的是K-Means聚类算法。
3. 使用K-Means进行聚类分析——实战示例
我们将使用以下Kaggle数据集:
数据集头部包含以下特征:
- Customer ID: 顾客编号
- Gender: 性别
- Age: 年龄
- City: 城市
- Membership Type: 会员类型
- Total Spend: 总消费额
- Items Purchased: 购买商品数量
- Average Rating: 平均评分
- Discount Applied: 是否使用折扣
- Days Since Last Purchase: 上次购买距今的天数
- Satisfaction Level: 顾客满意度
数据加载与预处理
首先,我们需要导入一些必要的库,并加载数据:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
# 加载数据
df = pd.read_csv('customer_data.csv')
# 查看数据头部
print(df.head())
假设数据集的内容已经成功加载,我们需要对数据进行一些预处理:
- 处理缺失值
- 标准化数据(因为K-Means对不同尺度的特征比较敏感)
# 处理缺失值
df = df.dropna() # 删除包含缺失值的行
# 对非数字数据进行处理(如性别、城市、会员类型)
df = pd.get_dummies(df, columns=['Gender', 'City', 'Membership Type'], drop_first=True)
# 提取数值型特征
features = df[['Age', 'Total Spend', 'Items Purchased', 'Average Rating', 'Days Since Last Purchase']]
# 标准化数据
scaler = StandardScaler()
scaled_features = scaler.fit_transform(features)
K-Means聚类
接下来,我们可以使用K-Means算法对顾客进行聚类。我们将使用Elbow Method来确定最佳的簇数K。
# 使用Elbow Method来确定最佳K值
inertia = []
for k in range(1, 11):
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(scaled_features)
inertia.append(kmeans.inertia_)
# 绘制肘部图
plt.plot(range(1, 11), inertia)
plt.title('Elbow Method for Optimal K')
plt.xlabel('Number of clusters')
plt.ylabel('Inertia')
plt.show()
这里我们简单解释一下Elbow Method(肘部法则)
基本原理
- 核心思想:随着聚类数量(K值)的增加,聚类的误差平方和(Inertia)会逐渐减小。Inertia 可以理解为每个数据点到其所属聚类中心的距离的平方和,它衡量了聚类的紧密程度,Inertia 值越小,表示聚类内的数据点越紧密,聚类效果越好。
- 肘部位置的确定:一开始,Inertia 会随着 K 值的增加而快速下降,因为更多的聚类可以更好地适应数据的分布,使得每个数据点更接近其聚类中心。然而,当 K 值增加到一定程度后,Inertia 的下降速度会明显变慢,此时的 K 值就类似于肘部的位置。
具体步骤
- 选择一系列 K 值:通常从较小的 K 值(如 1)开始,逐步增加到一个较大的值(如 10 或更多,具体取决于数据的规模和复杂性),对于每个 K 值,执行以下操作。
- 执行聚类算法:使用选定的 K 值运行聚类算法,例如 K-Means 算法。聚类算法会将数据划分为 K 个聚类,并计算每个聚类的中心。
- 计算 Inertia:根据聚类结果,计算每个数据点到其所属聚类中心的距离的平方和,得到该 K 值下的 Inertia 值。
- 绘制肘图:将 K 值作为横坐标,Inertia 值作为纵坐标,绘制出一条曲线。这条曲线通常会呈现出先陡峭下降,然后逐渐平缓的趋势。
选择最佳 K 值
- 观察肘部位置:在肘图中,寻找曲线从陡峭下降变为平缓的那个转折点,即肘部位置。这个位置对应的 K 值通常被认为是一个比较合适的聚类数量。
- 权衡与决策:虽然肘部位置提供了一个参考,但实际选择 K 值时还需要结合具体的业务场景和数据特点进行权衡。如果数据本身具有较为复杂的结构,可能需要选择稍大一些的 K 值以更好地捕捉数据的细节;而如果更注重模型的简洁性和可解释性,可能会倾向于选择较小的 K 值,即使肘部位置不是非常明显。
根据肘部图,选择合适的K值(K=3),然后训练模型并进行预测
# 选择K=3
kmeans = KMeans(n_clusters=3, random_state=42)
kmeans.fit(scaled_features)
数据可视化
def visualize_clusters(df, kmeans):
feature1 = df['Age']
feature2 = df['Total Spend']
cluster_labels = df['Cluster']
cluster_centers = kmeans.cluster_centers_
plt.figure(figsize=(10, 6)) # 调整图的大小
unique_labels = np.unique(cluster_labels)
colors = plt.cm.get_cmap('tab10', len(unique_labels)) # 使用更丰富的颜色映射
for label in unique_labels:
mask = cluster_labels == label
plt.scatter(feature1[mask], feature2[mask], c=[colors(label)], label=f'Cluster {label}', s=50)
# 绘制聚类中心
plt.scatter(cluster_centers[:, 0], cluster_centers[:, 1], s=200, c='red', marker='X', label='Centroids')
plt.title('Customer Segments', fontsize=16) # 增大标题字体
plt.xlabel('Age', fontsize=14) # 增大x轴标签字体
plt.ylabel('Total Spend', fontsize=14) # 增大y轴标签字体
plt.legend(fontsize=12) # 增大图例字体
plt.grid(True, linestyle='--', alpha=0.5) # 添加网格线,设置样式和透明度
plt.show()
visualize_clusters(df, kmeans)
在这一步中我们定义了一个visualize_clusters()函数,来进行结果可视化的展示,由于代码中我详细标注了每一步的具体作用,这里就不再过多赘述,我们来直接看它的效果。
可以看到分的还是很明确,但是由于数据量级不是特别大,所以聚类效果还是不太明显。
3.4 聚类结果
在上述内容中我们看到K-Means算法自动将顾客分成了三个组。每个组的顾客在某些特征上有相似之处,比如消费金额、购买商品数量等。通过这种方式,企业可以对不同类型的顾客采取不同的营销策略。这对于市场营销、产品推荐等应用非常有帮助。
4. 总结
无监督学习,特别是聚类分析,帮助我们在没有标签的情况下,发现数据的内在结构和模式。K-means是无监督学习中最基础、最常用的聚类方法之一,通过这个简单的示例,你已经掌握了如何进行基本的聚类分析。在实际应用中,数据的复杂性和问题的具体背景会影响到你选择的算法和参数,但这只是一个好的开始。
下次我们可以进一步探讨如何用无监督学习中的其他方法,其实今天我们已经接触到了一些无监督学习中降维(PAC)接下来我们会更进一步了解这次些算法的实际操作(如降维、异常检测等)来应对更复杂的实际问题。
希望这篇文章让你对无监督学习有了更清晰的理解,也让你对数据分析产生了兴趣。继续探索吧,数据的世界等着你去发现!