[学习笔记] [机器学习] 8. 聚类算法(聚类算法:K-means、K-means++;特征降维:Pearson相关系数、Spearman相关系数、PCA主成分分析)

  1. 视频链接
  2. 数据集下载地址:无需下载

1. 聚类算法简介

学习目标:

  • 掌握聚类算法实现过程
  • 知道K-means算法原理
  • 知道聚类算法中的评估模型
  • 说明K-means的优缺点
  • 了解聚类中的算法优化方式
  • 知道特征降维的实现过程
  • 应用K-means实现聚类任务

1.1 认识聚类算法

在这里插入图片描述

使用不同的聚类准则,产生的聚类结果不同。

1.2 聚类算法在现实中的应用

  • 用户画像、广告推荐、Data Segmentation、搜索引擎的流量推荐、恶意流量识别
  • 基于位置信息的商业推送、新闻聚类、筛选排序
  • 图像分割、降维、识别;离群点检测;信用卡异常消费;发掘相同功能的基因片段

在这里插入图片描述

1.3 聚类算法的概念

聚类算法:是一种典型的无监督学习算法,主要用于将相似的样本自动归到一个类别中。

在聚类算法中根据样本之间的相似性,将样本划分到不同的类别中,使用不同的相似度计算方法,会得到不同的聚类结果,常用的相似度计算方法有欧式距离法。

1.4 聚类算法与分类算法最大的区别

聚类算法是无监督的学习算法,而分类算法属于监督的学习算法。


小结

  • 聚类算法分类【了解】
    • 粗聚类
    • 细聚类
  • 聚类的定义【了解】
    • 一种典型的无监督学习算法
    • 主要用于将相似的样本自动归到一个类别中
    • 计算样本和样本之间的相似性,一般使用欧式距离

2. 聚类算法API的初步使用

学习目标:

  • 知道聚类算法API的使用

2.1 API介绍

sklearn.cluster.KMeans(n_clusters=8)

sklearn.cluster.KMeans 是 scikit-learn 库中的一个类,用于执行 K-Means 聚类算法。

  • 主要参数
    • n_clusters:int 类型,默认值为 8。要形成的簇数以及要生成的质心数。
    • init:{‘k-means++’, ‘random’}、可调用对象或形状为 (n_clusters, n_features) 的数组, 默认值为 ‘k-means++’。初始化方法。
    • n_init:‘auto’ 或 int 类型,默认值为 10。使用不同质心种子运行 k-means 算法的次数。最终结果是 n_init 连续运行中惯性最好的输出。
    • max_iter:int 类型,默认值为 300。单次运行 k-means 算法的最大迭代次数。
    • tol:float 类型,默认值为 1e-4。两次连续迭代之间簇中心差异的 Frobenius 范数相对容差,用于声明收敛。
    • verbose:int 类型,默认值为 0。详细模式。
    • random_state:int、RandomState 实例或 None,默认值为 None。确定质心初始化的随机数生成。
    • copy_x:bool 类型,默认值为 True。预计算距离时,首先居中数据更具数值精度。
    • algorithm:{“lloyd”, “elkan”, “auto”, “full”},默认值为 “lloyd”。使用的 K-means 算法。
  • 返回值
    • 该函数返回一个 KMeans 对象,可以使用其方法(如 fitpredict 等)对数据进行聚类分析。
  • 方法
    • fit(X[, y, sample_weight]):计算 K-Means 聚类。
    • fit_predict(X[, y, sample_weight]):计算聚类中心并预测每个样本所属的簇索引。
    • fit_transform(X[, y, sample_weight]):计算聚类中心并转换 X 以聚类距离。
    • get_params([deep]):获取此估计器的参数。
    • predict(X):预测最近的簇中心每个样本所属的簇。
    • score(X[, y, sample_weight]):对给定数据 X 的 KMeans 模型进行评分。
    • set_params(**params):设置此估计器的参数。
    • transform(X):将 X 转换为簇距离空间。

2.2 案例

随机创建不同二维数据集作为训练集,并结合k-means算法将其聚类,你可以尝试分别聚类不同数量的簇,并观察聚类效果:

在这里插入图片描述

聚类参数 n_cluster 传值不同,得到的聚类结果不同:

在这里插入图片描述

2.2.1 流程分析

  1. 导入工具库
  2. 创建数据集并显示
  3. 应用K-means
  4. 显示结果

2.2.2 代码实现

import matplotlib.pyplot as plt
from sklearn.datasets._samples_generator import make_blobs
from sklearn.cluster import KMeans
from sklearn.metrics import calinski_harabasz_score


# 1. 创建数据集
# X为样本特征y为样本簇类别,共1000个样本,每个样本有4个特征,共4个簇
# 簇中心在[-1, -1], [0, 0], [1, 1], [2, 2],簇方差分别为[0.4, 0.2, 0.2, 0.2]
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=9)

# 数据集可视化
plt.figure(dpi=300)
plt.scatter(X[:, 0], X[:, 1], marker='o')
plt.show()

在这里插入图片描述

# 2. 使用K-means进行聚类,并使用CH方法评估
y_pred = KMeans(n_clusters=2, random_state=9).fit_predict(X)

plt.figure(dpi=300)
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()

# 用CH方法评估聚类得分
print(calinski_harabasz_score(X=X, labels=y_pred))

在这里插入图片描述


分别尝试 n_clusters=2/3/4,然后查看聚类效果:

fig, axes = plt.subplots(1, 3, figsize=(20, 5),dpi=300)
n_clusters_ls = [2, 3, 4]
for idx, val in enumerate(n_clusters_ls):
    # 2. 使用K-means进行聚类,并使用CH方法评估
    y_pred = KMeans(n_clusters=val, random_state=9).fit_predict(X)
    
    axes[idx].scatter(X[:, 0], X[:, 1], c=y_pred)
    axes[idx].set_title(f"n_cluster={
      
      val}")

    # 用CH方法评估聚类得分
    print(f"n_clusters为{
      
      val}时的CH评分为:", calinski_harabasz_score(X=X, labels=y_pred))
plt.savefig("./不同n_clusters的聚类结果.png")
plt.show()
n_clusters为2时的CH评分为: 3116.1706763322227
n_clusters为3时的CH评分为: 2931.625030199556
n_clusters为4时的CH评分为: 5924.050613480169

在这里插入图片描述

CH分数越高越好


小结

  • API:sklearn.cluster.KMeans(n_clusters=8)【知道】
    • 参数:
      • n_clusters:开始的聚类中心数量
    • 方法:
      • estimator.fit_predict(x):计算聚类中心并预测每个样本属于哪个类别。
        • 相当于先调用fit(x),然后再调用predict(x)

3. 聚类算法实现流程

学习目标:

  • 掌握K-means聚类的实现步骤

  • k-means其实包含两层内容:
    • K:初始中心点个数(计划聚类数)
    • means:求中心点到其他数据点距离的平均值

3.1 K-means聚类的步骤

  1. 随机设置 K 个特征空间内的点作为初始的聚类中心
  2. 对于其他每个点计算到 K 个中心的距离,未知的点选择最近的一个聚类中心点作为标记类别
  3. 接着对着标记的聚类中心之后,重新计算出每个聚类的新中心点(平均值)
  4. 如果计算得出的新中心点与原中心点一样(质心不再移动),那么结束;否则重新进行第二步过程

通过下图解释实现流程:

在这里插入图片描述

动态图演示:

在这里插入图片描述

圆点是样本,×是聚类的中心

3.2 案例练习

在这里插入图片描述

步骤一:随机设置 K K K 个特征空间内的点作为初始的聚类中心(本案例中设置 P1 和 P2)

在这里插入图片描述

步骤二:对于其他每个点计算到 K K K 个中心的距离,未知的点选择最近的一个聚类中心点作为标记类别。

在这里插入图片描述

在这里插入图片描述

步骤三:接着对着标记的聚类中心之后,重新计算出每个聚类的新中心点(平均值)

在这里插入图片描述

步骤四:如果计算得出的新中心点与原中心点一样(质心不再移动),那么结束;否则重新进行第二步过程【经过判断,需要重复上述步骤,开始新一轮迭代】

在这里插入图片描述

注意:当每次迭代结果不变时,认为算法收敛,聚类完成,K-Means一定会停下,不可能陷入一直选质心的过程。


小结

  • K-means聚类实现流程【掌握】
  • 事先确定常数 K K K,常数 K K K 意味着最终的聚类类别数
  • 随机选定初始点为质心,并通过计算每一个样本与质心之间的相似度(这里为欧式距离),将样本点归到最相似的类中
  • 接着,重新计算每个类的质心(即为类中心),重复这样的过程,直到质心不再改变,最终就确定了每个样本所属的类别以及每个类的质心。
  • 注意:
    • 由于每次都要计算所有的样本与每一个质心之间的相似度,故在大规模的数据集上,K-Means算法的收敛速度比较慢。

4. 模型评估

学习目标:

  • 知道模型评估中的SSE、“肘”部法、SC系数和CH系数的实现原理

4.1 误差平方和(The sum of squares due to error,SSE)

举例:(下图中数据 -0.2, 0.4, -0.8, 1.3, -O.7 均为真实值和预测值的差)

在这里插入图片描述

在k-means中的应用:

S S E = ∑ i = 1 k ∑ p ∈ C i ∣ p − m i ∣ 2 \mathrm{SSE} = \sum^k_{i=1}\sum_{p \in C_i}|p-m_i|^2 SSE=i=1kpCipmi2

在这里插入图片描述

公式各部分内容:

在这里插入图片描述

上图中: k = 2 k=2 k=2

  • SSE图最终的结果,对图松散度的衡量(eg:SSE(左图) < SSE(右图))
  • SSE随着聚类迭代,其值会越来越小,直到最后趋于稳定:

注意:SSE算法内质心的选取时随机的,因此,在质心选取时,当两个质心初始距离较近时,可能产生不好的结果,因此SSE最后的结果是局部内最优解,而不是全局最优解。如下图所示:

在这里插入图片描述

如果质心的初始值选择不好,SSE只会达到一个不怎么好的局部最优解

在这里插入图片描述

4.2 “肘”方法(Elbow method)—— K值确定

在这里插入图片描述

  1. 对于 n n n 个点的数据集,迭代计算 k k k from i i i to n n n,每次聚类完成后计算每个点到其所属的簇中心的距离的平方和;
  2. 平方和是会逐渐变小的,直到 k = = n k==n k==n 时平方和为0,因为每个点都是它所在的簇中心本身。
  3. 在这个平方和变化过程中,会出现一个拐点也即“肘”点,下降率突然变缓时即认为是最佳的 k k k

在决定什么时候停止训练时,肘形判据同样有效,数据通常有更多的噪音,在增加分类无法带来更多回报时,我们停止增加类别
3轮廓系数法(Silhouette Coefficient)
结合了聚类的凝聚度(Cohesion)和分离度(Separation) ,用于评估聚类的效果:

4.3 轮廓系数法(Silhouette Coefficient,SC)

结合了聚类的凝聚度(Cohesion)和分离度(Separation),用于评估聚类的效果:

在这里插入图片描述

目的:内部距离 a a a 最小化,外部距离 b b b 最大化。

S ∈ [ − 1 , 1 ] S \in [-1, 1] S[1,1],其中 S S S 越大越好(接近于1),越小越差(接近于-1)

s ( i ) = b ( i ) − a ( i ) max ⁡ { a ( i ) , b ( i ) } = { 1 − a ( i ) b ( i ) , a ( i ) < b ( i ) 0 , a ( i ) = b ( i ) b ( i ) a ( i ) − 1 , a ( i ) > b ( i ) \begin{aligned} s(i) & = \frac{b(i) - a(i)}{\max\{a(i), b(i)\}}\\ & = \begin{cases} 1 - \frac{a(i)}{b(i)}, & a(i) < b(i)\\ 0, & a(i) = b(i)\\ \frac{b(i)}{a(i)} - 1, & a(i) > b(i) \end{cases} \end{aligned} s(i)=max{ a(i),b(i)}b(i)a(i)= 1b(i)a(i),0,a(i)b(i)1,a(i)<b(i)a(i)=b(i)a(i)>b(i)

计算样本 i i i 到同簇其他样本的平均距离 a ( i ) a(i) a(i) a ( i ) a(i) a(i) 越小样本 i i i 的簇内不相似度越小,说明样本 i i i 越应该被聚类到该簇。

计算样本 i i i 到最近簇 C j C_j Cj 的所有样本的平均距离 b ( j ) b(j) b(j),称样本 i i i 与最近簇 C j C_j Cj 的不相似度,定义为样本 i i i 的簇间不相似度: b ( i ) = min ⁡ { b ( i ) 1 , b ( i ) 2 , . . . , b ( i ) k } b(i) =\min\{b(i)_1, b(i)_2,..., b(i)_k\} b(i)=min{ b(i)1,b(i)2,...,b(i)k} b ( i ) b(i) b(i) 越大,说明样本 i i i 越不属于其他簇。

求出所有样本的轮廓系数后再求平均值就得到了平均轮廓系数。平均轮廓系数的取值范围为 [ − 1 , 1 ] [-1, 1] [1,1],系数越大,聚类效果越好。

簇内样本的距离越近,簇间样本距离越远。

案例

下图是500个样本含有2个feature的数据分布情况,我们对它进行SC系数效果衡量:

在这里插入图片描述

n_clusters = 2 The average silhouette_score is : 0.7049787496083262
n_clusters = 3 The average silhouette_score is : 0.5882004012129721
n_clusters = 4 The average silhouette_score is : 0.6505186632729437
n_clusters = 5 The average silhouette_score is : 0.56376469026194
n_clusters = 6 The average silhouette_score is : 0.4504666294372765

n_clusters分别为2,3,4,5,6时,SC系数如下,是介于[-1,1]之间的度量指标:

每次聚类后,每个样本都会得到一个轮廓系数,当它为1时,说明这个点与周围簇距离较远,结果非常好;当它为0,说明这个点可能处在两个簇的边界上;当值为负时,暗示该点可能被误分了。

从平均SC系数结果来看, K K K 取3、5、6是不好的,那么2和4呢?

K = 2 K=2 K=2 的情况:

在这里插入图片描述

K = 4 K=4 K=4 的情况:

在这里插入图片描述

  • n_clusters = 2时,第0簇的宽度远宽于第1簇;
  • n_clusters = 4时,所聚的簇宽度相差不大,因此选择 K = 4 K=4 K=4 作为最终聚类个数。

4.4 CH系数(Calinski-Harabasz Index)

Calinski-Harabasz:

类别内部数据的协方差越小越好,类别之间的协方差越大越好(换句话说:类别内部数据的距离平方和越小越好,类别之间的距离平方和越大越好),这样的 Calinski-Harabasz 分数 s s s 会高,分数 s s s 越高则聚类效果越好。

s ( k ) = t r ( B k ) t r ( W k ) m − k k − 1 s(k) = \frac{tr(B_k)}{tr(W_k)} \frac{m-k}{k-1} s(k)=tr(Wk)tr(Bk)k1mk

其中:

  • t r tr tr 为矩阵的迹, B k B_k Bk 为类别之间的协方差矩阵, W k W_k Wk 为类别内部数据的协方差矩阵
  • m m m 为训练集样本数
  • k k k 为类别数。

迹(trace),定义为主对角线数的和。对于一个矩阵: ( a 11 a 12 . . . a 1 n a 21 a 22 . . . a 2 n . . . . . . . . . . . . a n 1 a n 2 . . . a n n ) \begin{pmatrix} a_{11} & a_{12} & ... & a_{1n}\\ a_{21} & a_{22} & ... & a_{2n}\\ ... & ... & ... & ...\\ a_{n1} & a_{n2} & ... & a_{nn}\\ \end{pmatrix} a11a21...an1a12a22...an2............a1na2n...ann 则它的迹 t r tr tr的定义为 t r = a 11 + a 22 + . . . + a n n tr = a_{11} + a_{22} + ... + a_{nn} tr=a11+a22+...+ann

使用矩阵的迹进行求解的理解:矩阵的对角线可以表示一个物体的相似性

在机器学习里,主要为了获取数据的特征值,那么就是说,在任何一个矩阵计算出来之后,都可以简单化,只要获取矩阵的迹,就可以表示这一块数据的最重要的特征了,这样就可以把很多无关紧要的数据删除掉,达到简化数据,提高处理速度。

CH需要达到的目的:用尽量少的类别聚类尽量多的样本,同时获得较好的聚类效果


小结

  • sse【知道】
    • 误差平方和的值越小越好
  • 肘部法【知道】
    • 下降率突然变缓时即认为是最佳的 k k k
  • SC系数【知道】
    • 取值为[-1,1],其值越大越好
  • CH系数【知道】
    • 分数s越高则聚类效果越好
    • CH需要达到的目的:用尽量少的类别聚类尽量多的样本,同时获得较好的聚类效果。

5. 算法优化

学习目标:

  • 知道 k-means 算法的优缺点
  • 知道 canopy、K-means++、二分K-means、K-medoids 的优化原理
  • 了解kernel K-means、ISODATA、Mini-batch K-means的优化原理

k-means算法小结

  • 优点
    1. 原理简单(靠近中心点),实现容易
    2. 聚类效果中上(依赖 K K K 的选择)
    3. 空间复杂度 O ( N ) O(N) O(N),时间复杂度 O ( I ∗ K ∗ N ) O(I*K*N) O(IKN)

N N N 为样本点个数, K K K 为中心商个数, I I I 为迭代次数

  • 缺点
    1. 对离群点,噪声敏感(中心点易偏移)
    2. 很难发现大小差别很大的簇及进行增量计算
    3. 结果不一定是全局最优,只能保证局部最优(与 K K K 的个数及初值选取有关)

5.1 Canopy 算法配合初始聚类

Canopy 算法是一种“粗”聚类算法,它的速度较快,但精度较低。与传统的聚类算法(如 K-Means)不同,Canopy 聚类最大的特点是不需要事先指定 k 值(即聚类的个数),因此具有很大的实际应用价值

5.1.1 Canopy 算法配合初始聚类实现流程

Canopy 算法的步骤如下:

  1. 给定样本列表 L = x 1 , x 2 , … , x m L=x_1,x_2,\dots,x_m L=x1,x2,,xm 以及初始距离阈值为 T 1 T1 T1 T 2 T2 T2,且( T 1 > T 2 T1>T2 T1>T2)( T 1 T1 T1 T 2 T2 T2 可自己定义);
  2. 从列表 L L L 中任取一点 P P P,计算 P P P 到所有聚簇中心点的距离(如果不存在聚簇中心,那么就把点 P P P 作为一个新的聚簇),并选出与聚类中心最近的距离 D ( P , a j ) D(P,a_j) D(P,aj)
  3. 如果距离 D D D 小于 T 1 T1 T1,表示该节点属于该聚簇,添加到该聚簇列表中。
  4. 如果距离 D D D 小于 T 2 T2 T2,表示该节点不仅仅属于该聚簇,还表示和当前聚簇中心点非常近,所以将 P P P 从列表 L L L 中删除。

Canopy 算法可以用来进行“粗”聚类,得到 k 值以及大致的 K 个初始质心,再使用 K-means 进行进一步“细”聚类。这种 Canopy+K-means 的形式聚类算法聚类效果良好。

在这里插入图片描述

在这里插入图片描述

5.1.2 Canopy 算法的优缺点

优点

  1. K-means 对噪声抗干扰较弱,通过 Canopy 对比,将较小的 NumPoint 的 Cluster 直接去掉有利于抗干扰。
  2. Canopy 选择出来的每个 Canopy 的 centerPoint 作为 K 会更精确。
  3. 只是针对每个 Canopy 的内做 K-means 聚类,减少相似计算的数量

在 Canopy 算法中,NumPoint 指的是 Canopy 中包含点的数量。而 centerPoint 指的是 Canopy 中心点,即 Canopy 选择出来的每个 Canopy 的中心点。这些中心点可以作为 K-means 算法的初始质心,从而提高 K-means 算法的聚类效果。

缺点

  1. 算法中 T 1 T1 T1 T 2 T2 T2的确定问题,依旧可能落入局部最优解
  2. Canopy 算法得到的最终结果的值,聚簇之间是可能存在重叠的,但是不会存在某个对象不属于任何聚簇的情况。

5.2 K-means++ 算法

K-means++ 算法是一种为 K-means 聚类算法选择初始值(或“种子”)的算法。它是 NP-hard K-means 问题的一种近似算法,它是一种避免标准 K-means 算法有时发现的较弱聚类的方法。

K-means++ 算法仅仅只是在初始化簇中心的方式上做了改进,其它地方同 K-means 聚类算法一样。K-means++ 在初始化簇中心时的方法总结成一句话就是:逐个选取 k 个簇中心,且离其它簇中心越远的样本点越有可能被选为下一个簇中心。这样可以最大化避免初始簇中心在同一个簇中的情况,从而提高聚类效果。

P = D ( x ) 2 ∑ x ∈ X D ( x ) 2 P = \frac{D(x)^2}{\sum_{x\in X}D(x)^2} P=xXD(x)2D(x)2

其中:

  • P P P 表示每个样本点被选为下一个聚类中心的概率
  • D ( x ) D(x) D(x) 表示样本点 x x x 与当前已有聚类中心之间的最短距离(距离现有簇中心越远的样本点,越可能被选为下一个簇中心)
  • 在 K-means++ 算法中, D ( x ) D(x) D(x) 表示样本点 x x x 与当前已有聚类中心之间的最短距离。具体来说,假设当前已有 m m m 个聚类中心 c 1 , c 2 , … , c m c_1, c_2, \dots, c_m c1,c2,,cm,则 D ( x ) D(x) D(x) 可以通过以下公式计算得到:

D ( x ) = min ⁡ i = 1 m dist ( x , c i ) D(x) = \min_{i=1}^m \text{dist}(x, c_i) D(x)=i=1minmdist(x,ci)

其中 dist ( x , c i ) \text{dist}(x, c_i) dist(x,ci) 表示样本点 x x x 与聚类中心 c i c_i ci 之间的距离。距离的计算方式可以根据具体问题选择不同的距离度量方法,例如欧几里得距离、曼哈顿距离等。


为了方便后续计算,我们将 ∑ x ∈ X D ( x ) 2 \sum_{x\in X}D(x)^2 xXD(x)2 记为 A A A

在这里插入图片描述

首先我们选择 点2 作为质心,这样我们就可以求出不同点到质心的 P P P。然后我们根据不同点的概率 P P P 选择新的点作为质心。因为K-means++目的就是让选择的质心尽可能的分散

如下图中,如果第一个质心选择在圆心,那么最优可能选择到的下一个点在 P ( A ) P(A) P(A) 这个区域(根据颜色进行划分)。

在这里插入图片描述


K-means++ 算法流程如下

  1. 从数据集 X \mathcal{X} X 中随机(均匀分布)选取一个样本点作为第一个初始聚类中心 c i c_i ci
  2. 接着计算每个样本与当前已有聚类中心之间的最短距离,用 D ( x ) D(x) D(x) 表示;然后计算每个样本点被选为下一个聚类中心的概率 P ( x ) P(x) P(x) ,最后选择最大概率值所对应的样本点作为下一个簇中心。
  3. 重复第②步,直到选择出 k 个聚类中心。
  4. 使用标准 K-means 算法进行聚类。

标准 K-means 算法的流程如下

  1. 将每个样本点分配到离它最近的聚类中心所在的簇中。
  2. 计算每个簇的均值,并将其作为新的聚类中心。
  3. 重复第①、②步,直到聚类中心不再变化或达到最大迭代次数。

K-means++ 算法通过改进初始聚类中心的选择方式,可以有效避免标准 K-means 算法有时发现的较弱聚类,从而提高聚类效果。

5.3 二分K-means 算法

二分 K-means 算法是一种基于 K-means 算法改进的算法。它的主要思想是先从一个总簇开始,不断通过二分裂,直到分裂成 k 个簇为止

二分 K-means 算法流程如下:

  1. 将所有点看成一个簇;
  2. 对每个簇,进行如下操作:
    • 计算总误差(SSE);
    • 在给定的簇上进行 K-Means 聚类(k=2);
    • 计算将该簇一分为二之后的总误差(SSE);
  3. 选择使得误差 SSE 最小的那个簇进行划分操作(也就是对误差较大的簇进行划分);
  4. 重复第②、③步操作,直到达到用户指定的簇数目为止。

二分 K-means 算法可以有效地解决 K-means 算法收敛于局部最小值问题,提高聚类效果。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

二分K-means隐含的一个原则

因为聚类的误差平方和能够衡量聚类性能,该值越小表示数据点越接近于他们的质心,聚类效果就越好。所以需要对误差平方和最大的簇进行再一次划分,因为误差平方和越大,表示该簇聚类效果越不好,越有可能是多个簇被当成了一个簇,所以我们首先需要对这个簇进行划分。

二分K-means算法可以加速K-means算法的执行速度,因为它的相似度计算少了并且不受初始化问题的影响。因为二分K-means算法不存在随机点的选取,且每一步都保证了误差最小。

5.4 K-medoids(K-中心聚类算法)

K-medoids 和 K-means 是有区别的,不一样的地方在于中心点的选取。

  • K-means 中,将中心点取为当前cluster中所有数据点的平均值,所以对异常点很敏感。
  • K-medoids 中,将从当前cluster中选取到其他所有(当前cluster中的)点的距离之和最小的点作为中心点。

medoids:/ˈmɛdɔɪdz/ 中心点


K-medoids 算法(也称为 K-中心聚类算法)是一种经典的划分聚类技术,它将 n 个对象的数据集划分为 k 个簇,其中 k 值(即簇的数量)在算法执行之前已知(这意味着程序员必须在执行 K-medoids 算法之前指定 k 值)。

与 K-means 算法不同,K-medoids 算法选择实际数据点作为中心(medoids 或 exemplars),从而比 K-means 允许更好地解释聚类中心。此外,K-medoids 可以与任意不相似度量一起使用,而 K-means 通常需要欧几里得距离才能获得有效解决方案。因为 K-medoids 最小化成对不相似度之和而不是平方欧几里得距离之和,所以它比 K-means 更能抵抗噪声和异常值。

簇的 medoid 定义为簇中与所有对象的平均不相似度最小的对象,即它是簇中最中心位置的点。


在这里插入图片描述

算法流程

  1. 随机选择 k 个对象作为初始 medoids。
  2. 将每个剩余对象分配到离它最近的 medoid 所代表的簇中。
  3. 对于每个簇,计算每个成员对象对应的准则函数值,并选择准则函数值最小时对应的对象作为新的 medoid。
  4. 重复第②、③步操作,直到所有 medoid 对象不再发生变化或达到最大迭代次数。

其中,准则函数定义为一类中某个成员对象与其他成员对象之间距离之和。


相比K-means 算法而言,K-medoids 算法对噪声鲁棒性好

例:当一个 cluster 样本点只有少数几个,如(1, 1) (1, 2) (2, 1) (1000, 1000)。其中 (1000, 1000) 是噪声。

如果按照 K-means,质心大致会处在 (1, 1) (1000, 1000)中间。这显然不是我们想要的。

这时 k-medoids 就可以避免这种情况,他会在 (1,1) (1,2) (2,1) (1000,1000)中选出一个样本点使 cluster 的绝对误差最小,计算可知一定会在前三个点中选取。

k-medoids 只能对小样本起作用:如果样本大,那么速度就太慢了。而且当样本多的时候,少数几个噪音对 k-means 的质心影响也没有想象中的那么重,所以 k-means 的应用明显比 k-medoids 多


简单来说:

对于小数据集而言,可以使用 k-medoids,效果一般比K-means要好。但对于大数据集而言,还是要用K-means算法。

5.5 Kernel K-means 算法(了解)

Kernel K-means 算法是一种基于核方法的 K-means 算法,它可以处理非线性可分的数据。它通过将数据映射到高维空间,使得原本在低维空间中线性不可分的数据在高维空间中变得线性可分,从而提高聚类效果

Kernel K-means 算法的流程与标准 K-means 算法类似,但是在计算距离时使用了核函数来计算样本点之间的相似度。这样可以有效地解决标准 K-means 算法无法处理非线性可分数据的问题。

kernel k-means 实际上就是将每个样本进行一个投射,投射到高维空间的处理,然后再将处理后的数据使用普通的 k-means 算法思想进行聚类。

在这里插入图片描述

5.6 ISODATA 算法(了解)

ISODATA 算法(Iterative Self-Organizing Data Analysis Techniques Algorithm,迭代自组织数据分析技术算法)是一种改进的 k-means 算法。它在聚类过程中引入了对类别的评判标准,根据标准自动对某些类别进行合并或分裂,在一定程度上突破了对于给定类别数的限制。

该算法能够在聚类过程中根据各个类所包含样本的实际情况动态调整聚类中心的数目。如果某个类中样本分散程度较大(通过方差进行衡量)并且样本数量较大,则对其进行分裂操作;如果某两个类别靠得比较近(通过聚类中心的距离衡量),则对它们进行合并操作。

ISODATA 算法是一种重复自组织数据分析技术,计算数据空间中均匀分布的类均值,然后用最小距离技术将剩余像元进行迭代聚合,每次迭代都重新计算均值,且根据所得的新均值,对像元再进行分类。


特点

  • 类别数目随着聚类过程而变化
  • 对类别数会进行合并、分裂:
    • 合并:当聚类结果某一类中样本数太少,或两个类间的距离太近时
    • 分裂:当聚类结果中某一类的类内方差太大,将该类进行分裂

5.7 Mini Batch K-Means 算法(了解)

Mini Batch K-Means 算法是 K-Means 算法的一种优化方案,它适合大数据的聚类算法。该算法采用小批量的数据子集来减少计算时间,同时仍然试图优化目标函数。这里所谓的小批量是指每次训练算法时所随机抽取的数据子集,采用这些随机产生的子集进行训练算法,大大减小了计算时间,与其他算法相比,减少了 K-Means 的收敛时间,小批量 K-Means 产生的结果一般只略差于标准算法。

Mini Batch K-Means 算法可以减少 K-Means 算法的收敛时间,而且产生的结果效果只是略差于标准 K-Means 算法。

通常当样本量大于 1万 做聚类时,就需要考虑选用 Mini Batch K-Means 算法。

该算法的迭代步骤有两步:

  1. 从数据集中随机抽取一些数据形成小批量,把他们分配给最近的质心
  2. 更新质心

与 K-means 相比,数据的更新在每一个小的样本集上。对于每一个小批量,通过计算平均值得到更新质心,并把小批量里的数据分配给该质心。随着迭代次数的增加,这些质心的变化是逐渐减小的,直到质心稳定或者达到指定的迭代次数,停止计算。


小结

  • k-means 算法优缺点总结【知道】
    • 优点
      1. 原理简单(靠近中心点),实现容易
      2. 聚类效果中上(依赖 K 的选择)
      3. 空间复杂度 O ( N ) O(N) O(N),时间复杂度 O ( I K N ) O(IKN) O(IKN)
    • 缺点
      1. 对离群点,噪声敏感(中心点易偏移)
      2. 很难发现大小差别很大的簇及进行增量计算
      3. 结果不一定是全局最优,只能保证局部最优(与 K 的个数及初值选取有关)
  • 优化方法【知道】
优化方法 思路
Canopy + k-means Canopy 粗聚类配合 K-means
K-means++ 距离越远越容易成为新的质心
二分 K-means 拆除 SSE 最大的簇
k-medoids 和 K-means 选取中心点的方式不同
kernel K-means 映射到高维空间
ISODATA 动态聚类,可以更改 K 值的大小
Mini-batch K-means 大数据集分批聚类

6. 特征工程 —— 特征降维

学习目标:

  • 了解降维的定义
  • 知道通过低方差过滤实现降维过程
  • 知道相关系数实现降维的过程
  • 知道主成分分析法实现过程

6.1 降维

6.1.1 定义

在机器学习和统计学领域,降维是指在某些限定条件下,降低随机变量个数,得到一组“不相关”主变量的过程。降维可进一步细分为变量选择特征提取两大方法。

简单来说,降维就是采用某种映射方法,将原高维空间中的数据点映射到低维度的空间中。这样做的目的是为了减少冗余信息和噪声信息造成的误差,提高应用中的精度。常见的数据降维方法有:PCA、LDA、MDS、ISOMAP、SNE、T-SNE、AutoEncoder等。


简而言之,降维是指在某些限定条件下,降低随机变量(特征)个数,得到一组“不相关”主变量的过程。

关键在于:降低相关变量的个数

在这里插入图片描述


Q:比如对于一个数据集,有ABCDEFG这些特征,假如BCD这三个特征的相关性很高,那么是不是可以从BCD中选择一个特征(这里选择C)代替其他两个相似的特征(B和D),即数据集特征从原来的ABCDEFG变为了ACEFG。这样的理解正确吗?
A:这样的理解是正确的。在这个例子中,如果BCD三个特征的相关性很高,那么它们可能包含了大量重复的信息。在这种情况下,我们可以使用变量选择方法,从BCD中选择一个特征(例如C),并删除其他两个特征(B和D),以减少数据集中的冗余信息。这样,数据集中的特征就从原来的ABCDEFG变为了ACEFG。

当然,这只是降维的一种方法。另一种常用的降维方法是特征提取,它通过对原始特征进行某种变换,来生成新的、更少的特征。例如,在您提供的例子中,我们可以使用PCA等方法,将BCD三个特征转换为一个新的特征H,然后用H代替原来的BCD三个特征。这样,数据集中的特征就从原来的ABCDEFG变为了AEFGH。

总之,降维旨在减少数据集中的冗余信息和噪声信息,以提高模型在应用中的精度。


相关特征(correlated feature):

  • 相对湿度与降雨量之间的相关
  • 等等

正是因为在进行训练的时候,我们都是使用特征进行学习。如果特征本身存在问题或者特征之间相关性较强,对于算法学习预测会影响较大。

6.1.2 降维的两种方式

  1. 特征选择
  2. 主成分分析(可以理解一种特征提取的方式)

6.2 特征选择

6.2.1 定义

数据中包含冗余或无关变量(或称特征、属性、指标等)旨在从原有特征中找出主要特征

在这里插入图片描述

6.2.2 方法

  • Filter(过滤式):主要探究特征本身特点、特征与特征和目标值之间关联。
    • 方差选择法:低方差特征过滤
    • 相关系数
  • Embedded(嵌入式):算法自动选择特征(特征与目标值之间的关联)
    • 决策树:信息熵、信息增益
    • 正则化:L1、L2
    • 深度学习:
      • 卷积

6.2.3 低方差特征过滤

删除低方差的一些特征,前面讲过方差的意义。再结合方差的大小来考虑这个方式的角度。

  • 特征方差小:某个特征大多样本的值比较相近
  • 特征方差大:某个特征很多样本的值都有差别

方差是用来衡量一组数据离散程度的度量。它表示每一个变量(观察值)与总体均数之间的差异。方差越大,说明数据的波动越大;方差越小,说明数据的波动越小

6.2.3.1 API

sklearn.feature_selection.VarianceThreshold(threshold=0.0)
  • 作用sklearn.feature_selection.VarianceThreshold 是一个特征选择器,它可以移除所有低方差特征。这个特征选择算法只关注特征(X),而不关注期望的输出(y),因此可以用于无监督学习。
  • 参数
    • threshold:float, 默认值为0。训练集方差低于此阈值的特征将被移除。默认情况下,保留所有非零方差的特征,即移除所有样本中具有相同值的特征(但凡有一点不相同就保留)。
  • 属性
    • variances_:数组,形状为 (n_features,)。各个特征的方差。
    • n_features_in_:int。fit 期间看到的特征数。
    • feature_names_in_:ndarray,形状为 (n_features_in_,)。fit 期间看到的特征名称。仅当 X 具有全部为字符串的特征名称时定义。
  • 方法
    • fit(X, y=None):从 X 中学习经验方差。
    • fit_transform(X, y=None, **fit_params):拟合数据,然后转换它。
    • get_feature_names_out(input_features=None):根据所选特征掩码特征名称。
    • get_params(deep=True):获取此估计器的参数。
    • get_support(indices=False):获取所选特征的掩码或整数索引。
    • inverse_transform(X):反转转换操作。
    • set_params(**params):设置此估计器的参数。
    • transform(X):将 X 减少到所选特征。

6.2.3.2 数据计算

我们对某些股票的指标特征之间进行一个筛选,除去 'index''date''return' 列不考虑(这些类型不匹配,也不是所需要指标)。

一共有如下这些特征:

'pe_ratio', 'pb_ratio', 'market_cap', 'return_on_asset_net_profit', 'du_return_on_equity', 'ev', 'earnings_per_share', 'revenue', 'total_expense'

在这里插入图片描述

  • 分析:
    1. 初始化 VarianceThreshold,指定阀值方差
    2. 调用 fit_transform 方法
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.feature_selection import VarianceThreshold

data = pd.read_csv("./data/factor_returns.csv")

# 1. 实例化一个转换器类
transfer = VarianceThreshold(threshold=1)

# 2. 调用fit_transform方法
data = transfer.fit_transform(data.iloc[:, 1:10])
print("形状为:", data.shape)
print("删除低方差特征的结果为:\r\n", data)
形状为: (2318, 8)

删除低方差特征的结果为:
 [[ 5.95720000e+00  1.18180000e+00  8.52525509e+10 ...  1.21144486e+12
   2.07014010e+10  1.08825400e+10]
 [ 7.02890000e+00  1.58800000e+00  8.41133582e+10 ...  3.00252062e+11
   2.93083692e+10  2.37834769e+10]
 [-2.62746100e+02  7.00030000e+00  5.17045520e+08 ...  7.70517753e+08
   1.16798290e+07  1.20300800e+07]
 ...
 [ 3.95523000e+01  4.00520000e+00  1.70243430e+10 ...  2.42081699e+10
   1.78908166e+10  1.74929478e+10]
 [ 5.25408000e+01  2.46460000e+00  3.28790988e+10 ...  3.88380258e+10
   6.46539204e+09  6.00900728e+09]
 [ 1.42203000e+01  1.41030000e+00  5.91108572e+10 ...  2.02066110e+11
   4.50987171e+10  4.13284212e+10]]

6.2.4 相关系数

主要实现方式:

  1. 皮尔逊相关系数
  2. 斯皮尔曼相关系数

6.2.4.1 皮尔逊相关系数(Pearson Correlation Coefficient)

一、作用

皮尔逊相关系数是一种统计指标,用于反映两个变量之间相关关系的密切程度。它的取值范围为 [ − 1 , 1 ] [-1,1] [1,1]

  • 当系数接近1时,说明两个变量呈正相关关系,即一个变量增加,另一个也随之增加;
  • 当系数接近-1时,说明两个变量呈负相关关系,即一个变量增加,另一个会减少;
  • 当系数接近0时,说明两个变量之间没有线性关系。

二、公式计算案例(了解,不用记忆)

r = n ∑ x y − ∑ x ∑ y n ∑ x 2 − ( ∑ x ) 2 n ∑ y 2 − ( ∑ y ) 2 r = \frac{n\sum{xy} - \sum{x}\sum{y}}{\sqrt{n\sum{x^2} -(\sum{x})^2}\sqrt{n\sum{y^2} - (\sum{y})^2}} r=nx2(x)2 ny2(y)2 nxyxy

其中:

  • r r r:皮尔逊相关系数,用于衡量两个变量之间的线性关系。
  • n n n:样本数量。
  • x x x y y y:两个变量的值。
  • Σ x y Σxy Σxy:所有样本中 x x x y y y 的乘积之和。
  • Σ x Σx Σx Σ y Σy Σy:所有样本中 x x x y y y 的总和。
  • Σ x 2 Σx^2 Σx2 Σ y 2 Σy^2 Σy2:所有样本中 x 2 x^2 x2 y 2 y^2 y2 的总和。

举例:比如说我们计算年广告费投入与月均销售额。

在这里插入图片描述

那么之间的皮尔森相关系数怎么计算?

在这里插入图片描述

最终计算:

10 × 16679.09 − 346.2 × 422.5 10 × 14304.52 − 346. 2 2 10 × 19687.81 − 422. 5 2 = 0.9942 \frac{10\times 16679.09 - 346.2 \times 422.5}{\sqrt{10 \times 14304.52 - 346.2^2} \sqrt{10 \times 19687.81 - 422.5^2}} = 0.9942 10×14304.52346.22 10×19687.81422.52 10×16679.09346.2×422.5=0.9942

所以我们最终得出结论是:广告投入费与月平均销售额之间有高度的正相关关系。

皮尔森相关系数的取值范围为 [ − 1 , 1 ] [-1,1] [1,1]

三、特点

相关系数的值介于 [ − 1 , 1 ] [-1, 1] [1,1] 之间,即 − 1 ≤ r ≤ 1 -1 \le r \le 1 1r1。其性质如下:

  • r > 0 r > 0 r>0 时,表示两变量正相关; r < 0 r < 0 r<0 时,两变量为负相关
  • ∣ r ∣ = 1 |r| = 1 r=1 时,表示两变量为完全相关,当 r = 0 r = 0 r=0时,表示两变量间无相关关系
  • 当 $0<|r|<$1时,表示两变量存在一定程度的相关。且 ∣ r ∣ |r| r 越接近1,两变量间线性关系越密切; ∣ r ∣ |r| r 越接近于0,表示两变量的线性相关越弱。一般可按三级划分:
    • ∣ r ∣ < 0.4 |r| < 0.4 r<0.4 为低度相关
    • 0.4 ≤ ∣ r ∣ < 0.7 0.4 \le |r| < 0.7 0.4r<0.7 为显著性相关
    • 0.7 ≤ ∣ r ∣ < 1 0.7 \le |r| < 1 0.7r<1 为高度线性相关

四、API

from scipy.stats import pearsonr
  • 作用scipy.stats.pearsonr 是一个用于计算皮尔逊相关系数的函数,它可以衡量两个变量之间的线性关系。它还提供了用于检验非相关性的 p 值。
  • 参数
    • x:(N,) array_like,输入数组。
    • y:(N,) array_like,输入数组。
  • 返回值
    • r:float,皮尔逊相关系数,取值范围为 [-1, 1]。
    • p-value:float,双尾 p 值。

五、案例

from scipy.stats import pearsonr


x1 = [12.5, 15.3, 23.2, 26.4, 33.5, 34.4, 39.4, 45.2, 55.4, 60.9]
x2 = [21.2, 23.9, 32.9, 34.1, 42.5, 43.2, 49.0, 52.8, 59.4, 63.5]

r, p_value = pearsonr(x1, x2)
print("r:", r)
print("p-value:", p_value)
r: 0.9941983762371884
p-value: 4.922089955456964e-09

根据结果可知,x1x2 之间的皮尔逊相关系数为 0.9941983762371884,这说明两个变量之间存在着非常强的正相关关系。也就是说,当 x1 增加时,x2 也会随之增加。

双尾 p 值为 4.922089955456964e-09,这个值非常接近于 0。通常情况下,如果 p 值小于显著性水平(例如 0.05),则我们可以拒绝原假设(两个变量之间没有相关性),并认为两个变量之间存在着显著的相关性。在这种情况下,p 值非常小,因此我们可以认为 x1x2 之间存在着显著的相关性。

6.2.4.2 斯皮尔曼相关系数(Spearman’s rank correlation coefficient,Rank IC)

一、作用

斯皮尔曼等级相关系数(Spearman’s rank correlation coefficient,简称等级相关系数或秩相关系数)是一种衡量两个变量相关性的非参数指标。它利用单调函数评价两个统计变量的相关性。当数据中没有重复值,且当两变量完全单调相关时,斯皮尔曼相关系数为+1或−1。正的斯皮尔曼相关系数反映两个变量 X 和 Y 之间单调递增的趋势。负的斯皮尔曼相关系数反映两个变量 X 和 Y 之间单调递减的趋势。

二、公式(了解,不用记忆)

R a n k I C = 1 − 6 ∑ d i 2 n ( n 2 = 1 ) \mathrm{RankIC} = 1 - \frac{6\sum{d_i^2}}{n(n^2 = 1)} RankIC=1n(n2=1)6di2

其中:

  • RankIC:斯皮尔曼等级相关系数,用于衡量两个变量之间的单调关系。
  • d_i:第 i 个观测值的秩差,即两个变量的秩次之差。
  • n:样本数量。

Q:秩差是什么?
A:秩差(Rank Difference)是指在斯皮尔曼等级相关系数(Spearman’s rank correlation coefficient)的计算中,每个观测值的秩次之差。例如,如果您有两个变量 xy,并且对每个变量的值进行排序,那么每个观测值的秩差就是它在 x 中的秩次与它在 y 中的秩次之差。秩差用于计算斯皮尔曼等级相关系数,用于衡量两个变量之间的单调关系。

举个例子,假设有两组数据:

x = [1, 2, 3, 4]
y = [2, 3, 1, 4]

首先,我们需要对每组数据进行排序,并为每个数据分配一个秩次:

x_sorted = [1, 2, 3, 4]
x_ranks = [1, 2, 3, 4]

y_sorted = [1, 2, 3, 4]
y_ranks = [3, 1, 2, 4]

然后,我们可以计算每个观测值的秩差:

rank_differences = [2, -1, -1, 0]

最后,我们可以使用这些秩差来计算斯皮尔曼等级相关系数。


举例

在这里插入图片描述

三、特点

  • 斯皮尔曼相关系数表明 X(自变量)和 Y(因变量)的相关方向。如果当 X 增加时,Y 趋向于增加,斯皮尔曼相关系数则为正
  • 与之前的皮尔逊相关系数大小性质一样,取值仍然为 [ − 1 , 1 ] [-1,1] [11] 之间

斯皮尔曼相关系数比皮尔逊相关系数应用更加广泛

四、API

from scipy.stats import spearmanr
  • 作用scipy.stats.spearmanr 是一个用于计算斯皮尔曼等级相关系数的函数,它可以衡量两个变量之间的单调关系。它还提供了用于检验非相关性的 p 值。
  • 参数
    • a:(N,) array_like,输入数组。
    • b:(N,) array_like,输入数组,可选。
    • axis:int 或 None,可选。如果 axis=0(默认),则每列表示一个变量,行中包含观测值。如果 axis=1,则关系转置:每行表示一个变量,而列中包含观测值。如果 axis=None,则两个数组都将被展开。
    • nan_policy:{‘propagate’, ‘raise’, ‘omit’},可选。定义当输入包含 nan 时如何处理。可用的选项有(默认为 ‘propagate’):‘propagate’:返回 nan;‘raise’:抛出错误;‘omit’:忽略 nan 值进行计算。
    • alternative:{‘two-sided’, ‘less’, ‘greater’},可选。定义备择假设。默认为 ‘two-sided’。可用的选项有:‘two-sided’:相关性不为零;‘less’:相关性为负(小于零);‘greater’:相关性为正(大于零)。
  • 返回值
    • correlation:float 或 ndarray (2-D square)。斯皮尔曼相关矩阵或相关系数(如果只给出 2 个变量作为参数)。相关矩阵是正方形的,长度等于 a 和 b 组合在一起的总变量数(列或行)。
    • pvalue:float 或 ndarray (2-D square)。双尾 p 值。

五、案例

from scipy.stats import spearmanr


x1 = [12.5, 15.3, 23.2, 26.4, 33.5, 34.4, 39.4, 45.2, 55.4, 60.9]
x2 = [21.2, 23.9, 32.9, 34.1, 42.5, 43.2, 49.0, 52.8, 59.4, 63.5]

r, p_value = spearmanr(x1, x2)
print("r:", r)
print("p-value:", p_value)
r: 0.9999999999999999
p-value: 6.646897422032013e-64

根据结果可知,x1x2 之间的斯皮尔曼等级相关系数为 0.9999999999999999,这说明两个变量之间存在着非常强的正相关关系。也就是说,当 x1 增加时,x2 也会随之增加。

双尾 p 值为 6.646897422032013e-64,这个值非常接近于 0。通常情况下,如果 p 值小于显著性水平(例如 0.05),则我们可以拒绝原假设(两个变量之间没有相关性),并认为两个变量之间存在着显著的相关性。在这种情况下,p 值非常小,因此我们可以认为 x1x2 之间存在着显著的相关性。

6.3 主成分分析(Principal Component Analysis,PCA)

6.3.1 什么是主成分分析(PCA)

主成分分析(Principal Component Analysis,PCA)是一种常用的数据降维技术。它通过线性变换将一组可能相关的变量转换为一组线性不相关的变量,这些不相关的变量称为主成分。主成分分析可以通过保留低维主成分,忽略高维主成分来减少数据集的维数,同时保留数据集中对方差贡献最大的特征

定义:高维数据转化为低维数据的过程,在此过程中可能会舍弃原有数据、创造新的变量。

作用:数据维数压缩,尽可能降低原数据的维数(复杂度),损失少量信息。

应用:回归分析或者聚类分析当中。

对于信息一词,在决策树中会进行介绍

那么如何更好的理解这个过程呢?我们来看一张图。

在这里插入图片描述

要想看到一个茶壶的全貌,我们可以很明显的看到,第四张图是最容易的正式茶壶的全貌的。虽然看不到所有的细节,但不影响我们主要因素的获取。

6.3.2 API

sklearn.decomposition.PCA(n_components=None)
  • 作用sklearn.decomposition.PCA 是 scikit-learn 库中实现主成分分析(PCA)的类。它可以通过线性变换将一组可能相关的变量转换为一组线性不相关的变量,这些不相关的变量称为主成分。PCA 可以通过保留低维主成分,忽略高维主成分来减少数据集的维数,同时保留数据集中对方差贡献最大的特征。

  • 参数

    • n_components:int, float, None 或 str,默认值为 None。要保留的成分数。
      • 小数:表示保留百分之多少的信息
      • 整数:减少到多少特征
      • 如果 n_components 未设置,则保留所有成分:n_components == min(n_samples, n_features)。
      • 如果 n_components == ‘mle’ 并且 svd_solver == ‘full’,则使用 Minka 的 MLE 来猜测维数。使用 n_components == ‘mle’ 将解释 svd_solver == ‘auto’ 为 svd_solver == ‘full’。
      • 如果 0 < n_components < 1 并且 svd_solver == ‘full’,则选择使需要解释的方差量大于 n_components 指定的百分比的成分数。
      • 如果 svd_solver == ‘arpack’,则组件数必须严格小于 n_features 和 n_samples 的最小值。因此,None 情况下的结果为:n_components == min(n_samples, n_features) - 1。
    • copy:bool,默认值为 True。如果为 False,则传递给 fit 的数据将被覆盖,并且运行 fit(X).transform(X) 将无法获得预期结果,而应使用 fit_transform(X)。
    • whiten:bool,默认值为 False。当为 True(默认为 False)时,components_ 向量乘以 n_samples 的平方根,然后除以奇异值,以确保输出不相关且具有单位逐分量方差。白化将从转换信号中删除一些信息(组件的相对方差比例),但有时可以通过使其数据遵守硬连线假设来提高下游估计器的预测精度。
    • svd_solver:{‘auto’, ‘full’, ‘arpack’, ‘randomized’},默认值为 ‘auto’。
      • 如果 auto:根据 X.shape 和 n_components 选择求解器的默认策略:
        • 如果输入数据大于 500x500 并且要提取的组件数低于数据最小维度的 80%,则启用更高效的“随机化”方法。
        • 否则计算精确全 SVD 并在之后可选地截断。
      • 如果 full:运行精确全 SVD 调用标准 LAPACK 求解器通过 scipy.linalg.svd 并通过后处理选择组件。
    • tol:float,默认值为 0.0。svd_solver == ‘arpack’ 的收敛参数。
    • iterated_power:int 或 ‘auto’,默认值为 ‘auto’。svd_solver == ‘randomized’ 的幂迭代次数。
    • random_state:int, RandomState 实例或 None,默认值为 None。控制随机数生成器的种子;在选择随机化 svd 求解器时传递给 arpack 或 random_state。
  • 方法

    • fit(X[, y]):拟合模型。
    • fit_transform(X[, y]):拟合模型并执行转换。
    • get_covariance():计算数据协方差。
    • get_params([deep]):获取此估计器的参数。
    • get_precision():计算精度矩阵。
    • inverse_transform(X):将数据转换回原始空间。
    • score(X[, y]):返回平均对数似然。
    • score_samples(X):返回样本对数似然数组。
    • set_params(**params):设置此估计器的参数。
    • transform(X):将数据降维。

6.3.3 数据计算

先拿个简单的数据计算一下:

from sklearn.decomposition import PCA


data = [[2, 8, 4, 5], [6, 3, 0, 8], [5, 4, 9, 1]]

# 1. 实例化PCA,小数:保留多少信息
transfer = PCA(n_components=0.9)

# 2. 调用fit_transform方法
data_PCA = transfer.fit_transform(data)

print(f"保留90%的信息后,降维的结果为:\r\n{
      
      data_PCA}")
保留90%的信息后,降维的结果为:
[[ 1.28620952e-15  3.82970843e+00]
 [ 5.74456265e+00 -1.91485422e+00]
 [-5.74456265e+00 -1.91485422e+00]]
from sklearn.decomposition import PCA


data = [[2, 8, 4, 5], [6, 3, 0, 8], [5, 4, 9, 1]]

# 1. 实例化PCA,小数:保留多少信息
transfer = PCA(n_components=2)

# 2. 调用fit_transform方法
data_PCA = transfer.fit_transform(data)

print(f"降维到2维后的结果为:\r\n{
      
      data_PCA}")
降维到2维后的结果为:
[[ 1.28620952e-15  3.82970843e+00]
 [ 5.74456265e+00 -1.91485422e+00]
 [-5.74456265e+00 -1.91485422e+00]]

  • 降维的定义【了解】
    • 就是改变特征值,选择哪列保留,哪列删除。
    • 目标是得到一组“不相关”的主变量
  • 降维的两种方式【了解】
    • 特征选择
    • 主成分分析(可以理解一种特征提取的方式)
  • 特征选择【知道】
    • 定义:剔除数据中的冗余变量
    • 方法:
      • Filter(过滤式):主要探究特征本身特点、特征与特征和目标值之间关联
        • 方差选择法:低方差特征过滤(低方差意味着区别度低)
        • 相关系数
      • Embedded(嵌入式):算法自动选择特征(特征与目标值之间的关联)
        • 决策树:信息熵、信息增益
        • 正则化:L1、L2
  • 低方差特征过滤【知道】
    • 把方差比较小的某一列进行剔除
    • API:sklearn.feature_selection.VarianceThreshold(threshold=0.0)
      • 删除所有低方差特征
      • 注意:参数 threshold 一定要进行值的指定
  • 相关系数【掌握】
    • 主要实现方式:
      • 皮尔逊相关系数
      • 斯皮尔曼相关系数
    • 皮尔逊相关系数
      • 通过具体值的大小进行计算
      • 相对复杂
      • API:from scipy.stats import pearsonr
        • 返回值越接近1,相关性越强
        • 返回值越接近0,相关性越弱
    • 斯皮尔曼相关系数
      • 通过等级差进行计算
      • 比上一个(皮尔森相关系数)简单
      • API:from scipy.tats import spearmanr
        • 返回值越接近1,相关性越强
        • 返回值越接近0,相关性越弱
  • PCA【知道】
    • 定义:高维数据转换为低维数据,然后产生了新的变量
    • API:sklearn.decomposition.PCA(n_components=None)
      • n_components
        • 小数:保留百分之多少的信息
        • 整数:表示降低到几维

7. 案例:探究用户对物品类别的喜好细分

学习目标:

  • 应用 PCA 和 K-means 实现用户对物品类别的喜好细分划分

在这里插入图片描述

7.1 需求

无论您是根据精心计划的购物清单购物,还是让自己的心情指导您的购物,我们独特的食物习惯都定义了我们是谁。Instacart 是一款杂货订购和送货应用程序,旨在使您在需要时轻松地用您个人喜欢的和主食填满冰箱和食品储藏室。在通过 Instacart 应用程序选择产品后,个人购物者会查看您的订单并为您进行店内购物和送货。

Instacart 的数据科学团队在提供愉悦的购物体验方面发挥着重要作用。目前,他们使用交易数据开发模型,预测用户将再次购买哪些产品,首次尝试哪些产品,或在会话期间下一次添加到购物车中的产品。最近,Instacart 开源了这些数据 - 请参阅他们关于 300 万 Instacart 订单的博客文章。

在这场比赛中,Instacart 挑战 Kaggle 社区使用这些匿名的客户订单数据来预测用户下一个订单中将包含哪些先前购买过的产品。他们不仅寻找最佳模型,Instacart 还在寻找机器学习工程师来壮大他们的团队。

本次比赛的获胜者将获得现金奖励和快速通过招聘流程的机会。有关 Instacart 的令人兴奋的机会的更多信息,请查看他们的招聘页面或直接发送电子邮件至 [email protected] 与他们的招聘团队联系。

数据集链接Instacart Market Basket Analysis


数据如下:

  • order_products_prior.csv:订单与商品信息
    • 字段:order_id, product_id, add_to_cart_order, reordered
  • products.csv:商品信息
    • 字段:product_id, product_name, aisle_id, department_id
  • orders.csv:用户的订单信息
    • 字段:order_id, user_id, eval_set, order_number, …
  • aisles.csv:商品所属具体物品类别
    • 字段:aisle_id, aisle

7.2 分析

  1. 获取数据
  2. 数据基本处理
    1. 合并表格
    2. 交叉表合并
    3. 数据截取
  3. 特征工程:PCA
  4. 机器学习(k-means)
  5. 模型评估
    1. sklearn.metrics.silhouette_score(X, labels)
      1. 计算所有样本的平均轮廓系数
      2. X:特征值
      3. labels:被聚类标记的目标值

7.3 代码实现

7.3.0 导入库

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.feature_selection import VarianceThreshold
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

7.3.1 获取数据

# 1. 读取数据
order_product = pd.read_csv("./data/instacart-market-basket-analysis/order_products__prior.csv")
products = pd.read_csv("./data/instacart-market-basket-analysis/products.csv")
orders = pd.read_csv("./data/instacart-market-basket-analysis/orders.csv")
aisles = pd.read_csv("./data/instacart-market-basket-analysis/aisles.csv")

7.3.2 数据基本处理

7.3.2.1 合并表格

# 2. 数据基本处理
## 2.1 合并表格
# on:标签或列表。要连接的列或索引级别名称。这些必须在两个 DataFrame 中都能找到。如果 on 为 None 并且未在索引上合并,则默认为两个 DataFrame 中列的交集。
table_1 = pd.merge(order_product, products, on=["product_id", "product_id"])
table_2 = pd.merge(table_1, orders, on=["order_id", "order_id"])
table = pd.merge(table_2, aisles, on=["aisle_id", "aisle_id"])

7.3.2.2 交叉表合并

交叉表(Cross Tabulations)是一种常用的分类汇总表格,用于频数分布统计,主要价值在于描述了变量间关系的深刻含义。它可以计算两个(或更多)因子的简单交叉表。默认情况下,它会计算因子的频率表,除非传递了值数组和聚合函数。

例如,我们可以使用 pd.crosstab 函数来计算两个分类变量之间的交叉表。结果显示了每个变量中每个值与另一个变量中每个值的组合出现的次数。

下面是一个简单的例子,说明如何使用 pd.crosstab 函数来计算交叉表:

import pandas as pd

# 创建示例数据
data = {
    
    '性别': ['男', '女', '男', '女', '男', '女', '男', '男'],
        '喜欢的颜色': ['红', '红', '蓝', '绿', '蓝', '蓝', '红', '绿'],
        '数量': [1, 2, 3, 4, 5, 6, 7, 8]}

df = pd.DataFrame(data)

# 计算交叉表
ct = pd.crosstab(df['性别'], df['喜欢的颜色'])

print(ct)
df.head()

在这里插入图片描述

ct.head()

在这里插入图片描述

这段代码会输出以下结果:

喜欢的颜色  绿  红  蓝
性别                
女         1   1   1
男         1   2   2

在这个例子中,我们使用 pd.crosstab 函数计算了 性别喜欢的颜色 列的交叉表。结果显示了 性别 列中每个值与 喜欢的颜色 列中每个值的组合出现的次数。


推荐视频Pandas_透视表和交叉表

透视表(Pivot Table)是一种用于汇总和分析数据的工具。它可以根据一个或多个键对数据进行聚合,生成一个新的 DataFrame。透视表中的级别将存储在结果 DataFrame 的索引和列的 MultiIndex 对象(分层索引)中。透视表可以通过一个或多个键分组聚合 DataFrame 中的数据,通过 aggfunc 参数决定聚合类型,是 groupby 的高级功能。

交叉表(Cross Tabulations)是一种常用的分类汇总表格,用于频数分布统计,主要价值在于描述了变量间关系的深刻含义。默认情况下,它会计算因子的频率表,除非传递了值数组和聚合函数。交叉表用于计算一列数据对于另一列数据的分组个数(用于统计分组频率的特殊透视表)。

简而言之,透视表是一种进行分组统计的函数,而交叉表是特殊的透视表,当只统计分组频率时更方便


## 2.2 交叉表合并
table = pd.crosstab(table["user_id"], table["aisle_id"])
table.head()

在这里插入图片描述

这里我们使用交叉表合并是因为我们想要看一下"user_id"和商品类别"aisle_id"有什么关系。

7.3.2.3 数据截取

## 2.3 数据截取
table_clip = table[:1000]
table_clip.head()

在这里插入图片描述

7.3.3 特征工程:PCA主成分分析

# 3. 特征工程:PCA主成分分析
transfer = PCA(n_components=0.9)  # 保留90%的信息
data = transfer.fit_transform(table_clip)
data
array([[-2.27452872e+01, -7.32942365e-01, -2.48945893e+00, ...,
        -4.78491473e+00, -3.10742945e+00, -2.45192316e+00],
       [ 5.28638801e+00, -3.00176267e+01, -1.11226906e+00, ...,
         9.24145693e+00, -3.11309382e+00,  2.20144174e+00],
       [-6.52593099e+00, -3.87333123e+00, -9.23859508e+00, ...,
        -1.33929081e+00,  1.25062993e+00,  6.12717485e-01],
       ...,
       [ 1.31226615e+01, -2.77296885e+01, -4.62403246e+00, ...,
         7.40793534e+00,  1.03829352e+00, -1.39058393e+01],
       [ 1.64905900e+02, -8.54916188e+01,  1.90577481e-02, ...,
        -5.62014943e+00, -1.38488891e+01, -7.11424774e+00],
       [-1.60244724e+00,  1.82037661e+00,  8.55756408e+00, ...,
         3.69860152e+00,  2.82248188e+00, -3.79491023e+00]])
print("降维前特征数量为:", table_clip.shape)
print("降维后特征数量为:", data.shape)
降维前特征数量为: (1000, 134)
降维后特征数量为: (1000, 22)

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

import os
os.environ["OMP_NUM_THREADS"] = "4"

# 4. 机器学习:K-means聚类
estimator = KMeans(n_clusters=8, random_state=22)  # 分为8类
pred = estimator.fit_predict(data)
pred
array([0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
       0, 0, 0, 0, 1, 0, 0, 0, 7, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 7, 1, 0,
       1, 6, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 7,
       0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
       1, 0, 0, 0, 0, 0, 0, 2, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 3, 7, 1,
       1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
       0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 7, 0,
       0, 0, 0, 1, 0, 7, 0, 1, 0, 0, 6, 4, 0, 0, 0, 7, 0, 1, 0, 0, 1, 1,
       1, 1, 3, 0, 0, 1, 7, 0, 1, 0, 0, 7, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
       7, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 3,
       0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 7, 0, 0, 1, 0, 0,
       0, 0, 4, 5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0,
       7, 0, 0, 0, 4, 0, 0, 1, 0, 0, 0, 0, 7, 1, 3, 0, 0, 0, 3, 0, 0, 0,
       0, 1, 0, 7, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
       0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 4, 0,
       0, 0, 0, 0, 1, 0, 7, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1,
       0, 7, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 2, 1, 0, 0, 1, 0, 0, 0, 0, 1,
       0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 1, 0, 0,
       0, 0, 0, 4, 0, 0, 0, 1, 0, 1, 1, 7, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2,
       0, 7, 1, 7, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 7, 0, 0, 0,
       0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0,
       0, 1, 1, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 7,
       1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 1, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 7, 1, 0, 0, 1,
       0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 7, 0, 0, 0, 1, 7, 0, 0, 3, 1, 1, 1, 1, 0, 3, 0, 1, 3, 0, 0,
       0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
       0, 0, 0, 0, 1, 1, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 3, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 1, 1, 0, 1, 0, 0, 0,
       1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 7, 0, 0, 0, 0, 1, 7, 0, 0,
       0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 3, 0, 0,
       0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0,
       0, 0, 7, 0, 1, 1, 0, 0, 1, 0, 2, 1, 0, 0, 0, 7, 0, 7, 1, 0, 1, 0,
       0, 1, 0, 0, 1, 1, 0, 1, 0, 7, 0, 4, 0, 0, 0, 1, 0, 0, 0, 0, 7, 7,
       1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 2, 0, 7, 0, 1, 0, 1, 0, 0,
       0, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1,
       0, 0, 0, 0, 0, 0, 0, 1, 7, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
       3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 1, 1, 0, 3, 0, 0, 0, 3,
       1, 0, 0, 1, 7, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 1, 0, 0, 1, 2, 0])

7.3.5 模型评估

轮廓系数(Silhouette Coefficient)是一种用于评估聚类效果的指标。它通过计算每个样本的轮廓系数来衡量聚类效果。轮廓系数是通过计算每个样本的平均簇内距离(a)和平均最近簇距离(b)来计算的。每个样本的轮廓系数为 ( b − a ) / max ⁡ ( a , b ) (b - a) / \max(a, b) (ba)/max(a,b)。其中,b 是样本与不属于该样本的最近簇之间的距离。注意,当标签数量为 2 <= n_labels <= n_samples - 1 时,才定义轮廓系数。此函数返回所有样本的平均轮廓系数。

轮廓系数的取值范围为 [-1, 1]:

  • 当系数为 1 时,说明聚类效果很好;
  • 当系数为 -1 时,说明聚类效果很差;
  • 当系数接近 0 时,说明簇之间有重叠。

负值通常表示样本被分配到了错误的簇,因为不同的簇更相似。

在 scikit-learn 库中,可以使用 sklearn.metrics.silhouette_score 函数来计算轮廓系数。该函数需要提供数据矩阵 X 和标签数组 labels,并返回所有样本的平均轮廓系数。

# 5. 模型评估
score = silhouette_score(data, pred)
score
0.46400567259894415

我们看一下截取不同数量数据后的效果:

clip_num = [10, 50, 100, 500, 1000, 1500, 5000, 10000]

for clip_n in clip_num:
    ## 2.3 数据截取
    table_clip = table[:clip_n]

    # 3. 特征工程:PCA主成分分析
    transfer = PCA(n_components=0.9)  # 保留90%的信息
    data = transfer.fit_transform(table_clip)

    # 4. 机器学习:K-means聚类
    estimator = KMeans(n_clusters=8, random_state=22)  # 分为8类
    pred = estimator.fit_predict(data)

    # 5. 模型评估
    score = silhouette_score(data, pred)
    print(f"[数据量: {
      
      clip_n}] 分数为:{
      
      score*100:.4f}%")
[数据量: 10] 分数为:13.2716%
[数据量: 50] 分数为:33.6469%
[数据量: 100] 分数为:31.4929%
[数据量: 500] 分数为:44.9804%
[数据量: 1000] 分数为:46.4006%
[数据量: 1500] 分数为:38.5747%
[数据量: 5000] 分数为:38.0150%
[数据量: 10000] 分数为:37.5044%

可以看到,效果并不是很好,应该是我们使用的特征数量太少导致的。

猜你喜欢

转载自blog.csdn.net/weixin_44878336/article/details/131146649