Python 无监督学习实用指南:6~10(1)https://developer.aliyun.com/article/1426886
由于有 56,516 个正常样本,我们可以决定选择两个阈值(还要考虑异常离群值):
- 正常连接:
p[K](x) > 0.03
- 中度警报:0.03(涉及 3.1% 的正常样本,可以将其识别为假阳性)
- 高警报:0.015(在这种情况下,只有 1.2% 的正常样本可以触发警报)
此外,在第二个警报中,我们捕获到以下内容:
print(np.sum(Ya < 0.015))
输出如下:
2208
因此,只有一个异常样本具有p[K](x) > 0.015
(有 2,209 个向量),这证实了这种选择是合理的。 密度的直方图也证实了先前的结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pnK4OMiK-1681652675139)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/646b8603-c9d0-4176-81a6-8ce4046caf50.png)]
异常(左)和正常(右)密度的直方图
正态分布的右尾并不令人担忧,因为异常高度集中在左侧。 在这一领域,也存在大多数异常,因此也是最严重的。 原因与特定域严格相关(对于不同的请求,输入和输出字节可能非常相似),并且在更稳定的解决方案中,有必要考虑其他参数(例如:完整的 KDD Cup 99 数据集) 。 但是,出于教学目的,我们可以定义一个简单的函数(基于先前定义的阈值),以根据源字节和目标字节的数量(不是对数的)检查连接状态:
import numpy as np def is_anomaly(kd, source, destination, medium_thr=0.03, high_thr=0.015): xs = np.log(source + 0.1) xd = np.log(destination + 0.1) data = np.array([[xs, xd]]) density = np.exp(kd.score_samples(data))[0] if density >= medium_thr: return density, 'Normal connection' elif density >= high_thr: return density, 'Medium risk' else: return density, 'High risk'
现在,我们可以使用三个不同的示例来测试该函数:
print('p = {:.2f} - {}'.format(*is_anomaly(kd, 200, 1100))) print('p = {:.2f} - {}'.format(*is_anomaly(kd, 360, 200))) print('p = {:.2f} - {}'.format(*is_anomaly(kd, 800, 1800)))
输出如下:
p = 0.30 - Normal connection p = 0.02 - Medium risk p = 0.00000 - High risk
对于一般概述,还可以考虑源和目标字节密度的双变量图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lv2EjI1x-1681652675139)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/ce9eb95b-7f88-4a3b-9dc0-0faeb226b0bc.png)]
源和目标字节密度的双变量图
前面的屏幕快照确认,尽管攻击通常涉及大量的输入字节,但响应却与正常的响应非常相似,即使它们占据了该区域的最末端。 作为练习,我邀请读者使用整个 KDD Cup 99 数据集训练模型,并找出最佳阈值以检测非常危险和中等风险的攻击。
单类支持向量机
单类支持向量机(SVM)的概念已由 SchölkopfB,Platt JC,Shawe-Taylor JC,Smola AJ 和 Williamson RC 提出(《估计高维分布的支持》),作为一种将新颖性分类为从真实数据生成过程中抽取的样本或异常值的方法。 让我们从我们要实现的目标开始:找到一个无监督模型,在给定样本x[i]
的情况下,可以产生二进制输出y[i]
(通常,SVM 的结果是双极性的,分别为 -1 和 +1),因此,如果x[i]
属于内部,y[i] = 1
,如果x[i]
是一个异常值,则y [i] = -1
,在上述论文中,假设对构成训练集的大多数内线而言,结果是1
。 乍一看,这似乎是一个经典的监督问题。 但是,这不是因为不需要标签数据集。 实际上,给定一个包含m
样本的数据集X
,x[i] ∈ R^n
,模型将使用一个固定的类进行训练,目的是找到一个分离的超平面,该平面使X
与原点之间的距离最大化。 首先,让我们考虑一个简单的线性情况,如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D6FX7Won-1681652675140)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/0b1fe0d8-9c63-476f-85b5-359a89c61f10.png)]
线性单类 SVM 方案:训练集与原点分开,具有最大的边距
训练模型以找出使距原点的距离最大的超平面参数。 超平面一侧的所有样本均应为离群值,输出标签为+1
,而其余所有样本均被视为离群值,并且输出标签为-1
。 此标准似乎有效,但仅适用于线性可分离的数据集。 标准 SVM 通过将数据集(通过函数$1
)投影到特征空间D
上来解决此问题,在该特征空间D
中,它获得了这样的属性:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YF4P3ApB-1681652675140)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/7fde64b8-0a5e-4248-b156-7ac3ec831820.png)]
特别是,考虑到问题的数学性质,如果选择了内核,则投影在计算上变得轻巧。 换句话说,我们要使用一个具有以下属性的函数:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UOdBZ862-1681652675140)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/a1eb4e9a-d241-42fa-acbf-f655dc9eee26.png)]
投影函数$1
的存在保证存在于非常容易获得的条件(称为美世条件)下(即,在实子空间中,内核必须为正半 -定)。 这种选择的原因与解决问题的过程密切相关(更详细的解释可以在《机器学习算法第二版》找到)。 但是,不熟悉 SVM 的读者不必担心,因为我们不会讨论太多的数学细节。 要记住的最重要的一点是,不支持任何内核的通用投影会导致计算复杂性急剧增加(尤其是对于大型数据集)。
K(·, ·)
的最常见选择之一是径向基函数(已经在第 3 章,“高级聚类”中进行了分析):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bcukKIPz-1681652675140)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/24030c03-033f-4e35-b840-0349843b16b6.png)]
另一个有用的内核是多项式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nctQJPT3-1681652675140)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/ea90279d-b782-41ef-b394-ceb0393c3b50.png)]
在这种情况下,指数c
定义多项式函数的次数,该次数与特征空间的维数成正比。 但是,内核及其超参数的选择均取决于上下文,并且没有总有效的通用规则。 因此,对于每个问题,都需要进行初步分析,通常还需要进行网格搜索以做出最适当的选择。 一旦选择了内核,就可以用以下方式表示问题:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fI79Xmcy-1681652675141)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/71e19b2a-13bb-4db9-bfb2-e604dd90de9f.png)]
如果不进行全面讨论(超出本书的讨论范围),我们可以将注意力集中在一些重要元素上。 首先,决策函数如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KXgIxmRf-1681652675141)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/482bfa70-c8ff-46f3-9cd6-5380f0e60c9c.png)]
解决方案中涉及的数学过程使我们可以简化以下表达式,但出于我们的目的,最好保留原始表达式。 如果读者具有监督学习的基础知识,他们可以轻松地理解,权重向量与样本x[i]
投影之间的点积,可以确定x[i]
相对于超平面的位置。 实际上,如果两个向量之间的角度小于 90°(π / 2
),则点积是非负的。 当角度正好为 90°(即向量正交)时,它等于零;而当角度在 90° 至 180° 之间时,它等于负。 下图显示了此过程:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PBTSIw24-1681652675141)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/b17e49a6-e73b-4799-bbb4-75604fb98847.png)]
支持向量机中的决策过程
权向量正交于分离超平面。 样本x[i]
被确定为一个正常值,因为点积为正且大于阈值ρ
。 相反,x[j]
被标记为异常值,因为决策函数的符号为负。 项ξ[i] ≥ 0
被称为松弛变量,它们的引入是为了产生异常值和正常值间的更灵活的边界。实际上,如果这些变量都等于零(并且为简单起见,ρ = 1
),则优化问题的条件变为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WQYTWrlU-1681652675141)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/5a35ab70-84af-4bd0-aec6-dc88a81ec8ad.png)]
这意味着必须将所有训练样本视为内部值,因此必须选择分隔的超平面,以便所有x[i]
都在同一侧。 但是,松弛变量的使用通过定义软边界可以提供更大的灵活性。 每个训练样本都与变量x[i]
相关联,当然,问题在于将其最小化。 但是,通过这种技巧,即使继续将其识别为离群值,也可以将一些边界样本放置在超平面的另一侧(足够靠近它)。 要考虑的最后一个元素是此上下文中最重要的元素,并且涉及超参数ν ∈ (0, 1)
。 在上述论文中,作者证明,每当ρ ≠ 0
时,ν
都可以解释为训练样本分数的上限,实际上是离群值。 在本章开始时,我们已经指出,在新颖性检测问题中,数据集必须是干净的。 不幸的是,并非总是如此。 因此,v
和松弛变量的联合使用使我们也能够处理包含一小部分离群值的数据集。 就概率而言,如果X
是从部分被噪声破坏的数据生成过程中提取的,则ν
是在X
中发现异常值的概率。
现在,基于一个用元组(年龄,身高)识别的学生数据集分析一个二维示例。 我们将从二元高斯分布中得出 2,000 个内点,并均匀采样 200 个测试点:
import numpy as np nb_samples = 2000 nb_test_samples = 200 X = np.empty(shape=(nb_samples + nb_test_samples, 2)) X[:nb_samples] = np.random.multivariate_normal([15, 160], np.diag([1.5, 10]), size=nb_samples) X[nb_samples:, 0] = np.random.uniform(11, 19, size=nb_test_samples) X[nb_samples:, 1] = np.random.uniform(120, 210, size=nb_test_samples)
由于比例尺不同,因此在训练模型之前最好对数据集进行标准化:
from sklearn.preprocessing import StandardScaler ss = StandardScaler() Xs = ss.fit_transform(X)
以下屏幕快照显示了标准化数据集的图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z1od4Pvs-1681652675142)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/0f2a66e7-beca-4734-ac68-5aa079d91c2c.png)]
单类 SVM 示例的数据集
主斑点主要由内部像素组成,一部分测试样本位于同一高密度区域。 因此,我们可以合理地假设在包含所有样本的数据集中有大约 20% 的异常值(因此ν = 0.2
)。 当然,这种选择是基于我们的假设,在任何实际场景中, ν
的值必须始终反映数据集中预期异常值的实际百分比 。 当此信息不可用时,最好从较大的值开始(例如ν = 0.5
),然后再减小它直到找到最佳配置为止(即 ,则错误分类的可能性最小)。
同样重要的是要记住,训练过程有时会找到次优的解决方案。 因此,可以将一些孤立点标记为孤立点。 在这些情况下,最佳策略是测试不同内核的效果,例如,在处理多项式内核时,增加它们的复杂度,直到找到最佳解决方案(不一定排除所有错误)为止。
现在让我们使用 RBF 内核(特别适合于高斯数据生成过程)初始化 scikit-learn OneClassSVM
类的实例,并训练模型:
from sklearn.svm import OneClassSVM ocsvm = OneClassSVM(kernel='rbf', gamma='scale', nu=0.2) Ys = ocsvm.fit_predict(Xs)
我们根据以下公式选择了建议值gamma='scale'
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PDZC3Tsc-1681652675142)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/9f454540-275e-4d62-bf25-1e2fb9f528be.png)]
通常,这样的选择是最好的起点,可以更改(根据结果是否可接受而增加或减少)。 在我们的情况下,由于数据集是二维(n = 2
)和归一化的(std(X) = 1
),因此γ = 0.5
单位方差高斯分布(因此,我们应该期望它是最合适的选择)。 在这一点上,我们可以通过突出显示异常值来绘制结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bIebKa2I-1681652675142)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/5095f406-a826-4c47-bc76-30fd5e3efdf1.png)]
分类结果(左)。 测试集中的异常值(右)
从左图可以看出,该模型已成功识别出数据集的较高密度部分,并且还在密集 Blob 的外部区域中将一些样本标记为离群值。 它们对应于二元高斯条件下具有较低概率的值,在我们的情况下,我们假设它们是应过滤掉的噪声样本。 在右图中,可能只看到离群区域,这当然是高密度斑点的补充。 我们可以得出结论,即使是一类 SVM,即使有点倾向于过拟合,它也可以帮助我们以极小的错误概率识别新颖性。 这也是由于数据集的结构(但是,在许多情况下很常见),可以使用 RBF 内核轻松地对其进行管理。 不幸的是,对于高维数据,通常会丢失这种简单性,并且必须进行更彻底的超参数搜索才能使错误率最小化。
隔离森林的异常检测
Liu FT,Ting KM 和 Zhou Z 在文章《隔离森林》中提出了一种非常强大的异常检测方法。 它基于集成学习的总体框架。 由于该主题范围很广,并且主要涵盖在有监督的机器学习书籍中,因此,如果有必要,我们邀请读者检查建议的资源之一。 相反,在这种情况下,我们将在不非常强力引用所有基础理论的情况下描述模型。
首先,我们说森林是一组称为决策树的独立模型。 顾名思义,它们比算法更实用,是对数据集进行分区的一种实用方法。 从根开始,为每个节点选择一个特征和一个阈值,并将样本分为两个子集(非二叉树不是这样,但是通常,所有涉及的树都是这些模型都是二叉树),如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RMEgqnDe-1681652675143)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/e2cec22b-e13b-4cb0-a353-000c8a4ba3b4.png)]
二叉决策树的通用结构
在有监督的任务中,选择元组(特征,阈值)是根据使子项的杂质最小化的特定标准选择的。 这意味着目标通常是拆分节点,以使结果子集包含属于单个类的大多数样本。 当然,很容易理解,当所有叶子都是纯净的或达到最大深度时,该过程结束。 相反,在此特定上下文中,我们从一个非常特殊(但经过经验证明)的假设开始:如果属于隔离森林的树木每次都选择随机特征和随机阈值进行生长,则从根到包含任何异常值的叶子的路径的平均长度,比隔离异常值所需的路径更长。 通过考虑一个二维示例,可以很容易地理解这一假设的原因,如作者所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KeXnWmbx-1681652675143)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/7b91e898-5147-47c5-b273-a25e89bfe857.png)]
二维随机分区。 在左侧,孤立了一个内部。 在右侧,检测到属于低密度区域的异常值
可以观察到,正常值通常属于高密度区域,需要更多的分区来隔离样本。 相反,由于所需的粒度与斑点的密度成比例,因此可以使用较少的划分步骤来检测低密度区域中的异常值。 因此,建立了一个隔离森林,其目的是测量所有内部节点的平均路径长度,并将其与新样本所需的平均路径长度进行比较。 当这样的长度较短时,成为异常值的可能性增加。 作者提出的异常分数基于指数函数:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uJMd6V8G-1681652675143)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/63000df1-9ce2-4ed6-910d-da875a7cb63b.png)]
在上一个公式中,m
是属于训练集X
的样本数,avg(h(x[i]))
是考虑所有树的x[i]
的平均路径长度,c(m)
是仅取决于m
的规范化项。 当s(x[i], m) → 1
时,样本x[i]
被识别为异常。 因此,由于s(·)
的界限介于 0 和 1 之间,如果我们将阈值设为 0.5,则正常样本与s(x[i], m)<< 0.5
。
现在让我们考虑一下葡萄酒数据集,其中包含 178 个样本x[i] ∈ ℜ^13
,其中每个特征都是特定的化学性质(例如,酒精,苹果酸,灰分等),并训练一个隔离森林来检测一种新葡萄酒是否可以被认为是一种正常值(例如,现有品牌的变体)还是异常值,因为它的化学特性与每种现有样本不同。 第一步包括加载和规范化数据集:
import numpy as np from sklearn.datasets import load_wine from sklearn.preprocessing import StandardScaler wine = load_wine() X = wine['data'].astype(np.float64) ss = StandardScaler() X = ss.fit_transform(X)
现在,我们可以实例化IsolationForest
类并设置最重要的超参数。 第一个是n_estimators=150
,它通知模型训练 150 棵树。 另一个基本参数(类似于一类 SVM 中的v
)称为contamination
,其值表示训练集中异常值的预期百分比。 当我们信任数据集时,我们选择了等于 0.01(1%)的值来解决数量可忽略不计的奇怪样本的存在。 出于兼容性原因,已插入behaviour='new'
参数(请查看官方文档以获取更多信息),并且random_state=1000
保证实验的可重复性。 一旦类被初始化,就可以训练模型:
from sklearn.ensemble import IsolationForest isf = IsolationForest(n_estimators=150, behaviour='new', contamination=0.01, random_state=1000) Y_pred = isf.fit_predict(X) print('Outliers in the training set: {}'.format(np.sum(Y_pred == -1)))
上一片段的输出为:
2
因此,隔离森林已成功识别出 178 个内岛中的 176 个。 我们可以接受此结果,但是与往常一样,我建议调整参数以获得与每种特定情况都兼容的模型。 此时,我们可以生成一些嘈杂的样本:
import numpy as np X_test_1 = np.mean(X) + np.random.normal(0.0, 1.0, size=(50, 13)) X_test_2 = np.mean(X) + np.random.normal(0.0, 2.0, size=(50, 13)) X_test = np.concatenate([X_test_1, X_test_2], axis=0)
测试集分为两个块。 第一个数组X_test_1
包含噪声水平相对较低的样本(σ = 1
),而第二个数组X_test_2
包含更多噪声样本(σ = 2
)。 因此,我们期望第一组的异常值较低,而第二组的数量较大。 数组X_test
是两个测试集的有序连接。 现在让我们预测状态。 由于这些值是双极性的,我们想将它们与训练结果区分开,因此我们将乘以预测时间2
(即,-1
表示训练集中的离群值,1
训练集中的离群值, 测试集中的-2
异常值,测试集中的2
异常值):
Y_test = isf.predict(X_test) * 2 Xf = np.concatenate([X, X_test], axis=0) Yf = np.concatenate([Y_pred, Y_test], axis=0) print(Yf[::-1])
输出如下:
[ 2 2 -2 -2 -2 -2 -2 2 2 2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 2 -2 2 2 -2 -2 -2 2 -2 -2 -2 -2 2 2 -2 -2 -2 -2 -2 -2 2 2 -2 2 -2 2 -2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 -2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 -1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
由于顺序被保留和反转,我们可以看到属于X_test_2
(高方差)的大多数样本被归类为异常,而大多数低方差样本被识别为常值。 为了得到进一步的视觉确认,我们可以执行 t-SNE 降维,考虑到最终结果是二维分布,其 Kullback-Leibler 与原始(13 维)的散度最小。 这意味着所得维数的可解释性非常低,并且只能使用该图来理解二维空间的哪些区域更可能被 inlier 占据:
from sklearn.manifold import TSNE tsne = TSNE(n_components=2, perplexity=5, n_iter=5000, random_state=1000) X_tsne = tsne.fit_transform(Xf)
下图显示了结果图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ryGLtovL-1681652675143)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/eb3a4c8f-2ebe-4c56-bf96-92427af3c8c2.png)]
用于葡萄酒数据集的新颖性检测的 t-SNE 图
可以看到,许多接近训练离群点的样本本身就是离群点,并且通常,几乎所有远测样本都是离群点。 但是,由于维数的减少,很难得出更多的结论。 但是,我们知道,当噪声足够小时,找到内点的可能性就很大(这是合理的结果)。 作为练习,我请读者检查一下单个化学性质,以及对于每个或每组,找出哪个阈值可以将一个离群值转换为离群值(例如,回答此问题:与训练集兼容的最大酒精含量是多少?)。
总结
在本章中,我们讨论了概率密度函数的性质以及如何将其用于计算实际概率和相对可能性。 我们已经看到了如何创建直方图,这是将值分组到预定义的 bin 中后代表值频率的最简单方法。 由于直方图有一些重要的局限性(它们非常不连续并且很难找到最佳的 bin 大小),我们引入了核密度估计的概念,这是使用平滑函数估计密度的一种稍微复杂的方法。
我们分析了最常见内核(高斯, Epanechnikov,指数和均匀)的属性,以及两种可用于找出每个数据集最佳带宽的经验方法。 使用这种技术,我们试图基于合成数据集解决一个非常简单的单变量问题。 我们分析了 KDD Cup 99 数据集的 HTTP 子集,其中包含几个正常和恶意网络连接的日志记录。 并且我们已经使用 KDE 技术基于两个阈值创建了一个简单的异常检测系统,并且我们还解释了在处理这类问题时必须考虑哪些因素。
在最后一部分中,我们分析了可用于执行新颖性检测的两种常用方法。 一类 SVM 利用核函数将复杂的数据集投影到可以线性分离的特征空间上。 下一步基于这样的假设:所有训练集(一小部分除外)都是内在者,因此它们属于同一类。 训练该模型的目的是最大程度地缩小内部节点与特征空间原点之间的距离,并且结果基于样本相对于分离超平面的位置。 相反,孤立森林是一种集成模型,基于以下假设:离群值从随机训练的决策树中的根到样本的路径平均较短。
因此,在训练森林之后,可以考虑给定新样本的平均路径长度来计算异常分数。 当该分数接近 1 时,我们可以得出结论,异常的可能性也很大。 相反,非常小的得分值表明该新颖性是潜在的内在值。
在下一章中,我们将讨论降维和字典学习的最常用技术,当有必要管理具有大量特征的数据集时,这些技术将非常有用。
问题
- 一个人身高 1.70m 的概率为
p(Tall) = 0.75
,而明天要下雨的概率为P(Rain) = 0.2
。p(Tall, Rain)
的概率是多少? (即一个人身高 1.70m,明天要下雨的概率)。 - 给定数据集
X
,我们构建了一个具有 1,000 个桶的直方图,我们发现其中许多是空的。 为什么会这样? - 直方图包含三个分别具有 20、30 和 25 个样本的桶。 第一个容器的范围为
0 < x < 2
,第二个2 < x < 4
,第三4 < x < 6
。P(x) > 2
的大概概率是多少? - 给定正态分布
N(0, 1)
,可以将p(x) = 0.35
的样本x
视为异常吗? - 具有 500 个样本的数据集
X
具有std(X) = 2.5
和IQR(X) = 3.0
。 最佳带宽是多少? - 一位专家告诉我们,分布在两个值附近都达到了峰值,并且密度突然从峰均值下降了 0.2 个标准差。 哪种内核最合适?
- 给定样本
x
(从 10,000 个样本的流人口中收集),我们不确定这是异常还是新颖,因为p(x) = 0.0005
。 再进行 10,000 次观察后,我们重新训练模型,x
保持p(x) < 0.001
。 我们可以得出结论x
是异常吗?
进一步阅读
Epanechnikov V A, Non-parametric estimation of a multivariate probability density, Theory of Probability and its Applications, 14, 1969
Parzen E, On Estimation of a Probability Density Function and Mode, The Annals of Mathematical Statistics, 1962
Sheather S J, The performance of six popular bandwidth selection methods on some real data sets (with discussion), Computational Statistics, 7, 1992
Schölkopf B, Platt J C, Shawe-Taylor J C, Smola A J, Williamson R C, Estimating the support of a high-dimensional distribution, Neural Computation, 13/7, 2001
Liu F T, Ting K M, Zhou Z, Isolation forest, ICDM 2008, Eighth IEEE International Conference on Data Mining, 2008
Dayan P, Abbott L F, Theoretical Neuroscience, The MIT Press, 2005
Machine Learning Algorithms Second Edition, Bonaccorso G., Packt Publishing, 2018
七、降维和成分分析
在本章中,我们将介绍和讨论一些非常重要的技术,这些技术可用于执行降维和成分提取。 在前一种情况下,目标是将高维数据集转换为低维数据集,以尽量减少信息丢失量。 后者是找到可以混合的原子字典以构建样本所需的过程。
特别是,我们将讨论以下主题:
- 主成分分析(PCA)
- 奇异值分解(SVD)和增白
- 核 PCA
- 稀疏的 PCA 和字典学习
- 因子分析
- 独立成分分析(ICA)
- 非负矩阵分解(NNMF)
- 潜在狄利克雷分布(LDA)
技术要求
本章将介绍的代码需要以下内容:
- Python3.5+(强烈建议使用 Anaconda 发行版)
- 以下库:
- SciPy 0.19+
- NumPy 1.10+
- Scikit-Learn 0.20+
- Pandas 0.22+
- Matplotlib 2.0+
- Seaborn 0.9+
主成分分析(PCA)
减少数据集维数的最常见方法之一是基于样本协方差矩阵的分析。 通常,我们知道随机变量的信息内容与其方差成正比。 例如,给定多元高斯,熵是我们用来测量信息的数学表达式,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h0HbsDjI-1681652675144)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/998f8f17-4c20-4dfa-952f-7c14ed957bae.png)]
在前面的公式中,Σ
是协方差矩阵。 如果我们假设(不失一般性)Σ
是对角线,那么很容易理解,熵(成比例地)大于每个单个分量的方差σ[i]^2
。 这不足为奇,因为方差低的随机变量集中在均值附近,出现意外的可能性低。 另一方面,当σ^2
变得越来越大时,潜在结果随着不确定性而增加,不确定性与信息量成正比。
当然,组件的影响通常是不同的; 因此,主成分分析(PCA)的目标是,可以找到可以将其投影到较低维子空间的样本的线性变换,来保持最大的初始方差量。 实际上,让我们考虑一个数据集X ∈ G^(m×n)
:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hn6a7vu0-1681652675144)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/f228a482-b17a-47db-a19c-cdce3779555f.png)]
我们要查找的线性变换是一个新的数据集,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jTlaxDBZ-1681652675144)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/65cd1e88-dafd-4d51-93c0-05433565fd21.png)]
应用了这样的转换后,我们期望具有以下内容:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T4DAOP1h-1681652675144)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/8d580e00-60fa-4ec8-868e-5dcb5b9752ee.png)]
让我们开始考虑样本协方差矩阵(出于我们的目的,我们也可以采用有偏估计); 为简单起见,我们还将假设X
的均值为零:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zoPYNqXc-1681652675144)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/94f59483-b3b0-42b8-881b-8f88e1a42b51.png)]
这样的矩阵是对称的且是正半定的(如果您不熟悉这些概念并不重要,但是它们对于证明以下步骤非常重要),因此其特征向量构成了正交标准。 快速回顾一下,如果A
是方阵,则将v[i]
的向量称为与特征值v[i]
,如果满足以下条件:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O8zGtGaP-1681652675145)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/84f43f25-9b2e-4994-b580-27d4922e5c70.png)]
换句话说,特征向量被转换为自身的扩展或压缩版本(不会发生旋转)。 证明协方差矩阵的特征向量定义协方差分量的方向(即数据集具有特定协方差分量的方向)并不难(但将省略所有数学细节)。 原因很简单; 实际上,在变换之后,新的协方差矩阵(变换后的数据集Z
)是不相关的(即,它是对角线的),因为新轴与协方差分量对齐。 这意味着将向量(例如,v[0] = (1, 0, 0, ..., 0)
)转换为σ[i]^2 v[i]
,因此它是一个特征向量,其相关特征值与第i
个分量的方差成比例 。
因此,为了找出可以丢弃的元素,我们可以对特征值进行排序,以便满足以下条件:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mVtkGb7s-1681652675145)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/1fc1b1d5-1d32-426c-9723-8a559c1b09b0.png)]
相应的特征向量v[1], v[2], ..., v[n]
分别确定对应最大方差的成分,依此类推,直到最后一个。 形式上,我们将特征向量定义为主成分; 因此,第一个主成分是与最大方差相关的方向,第二个主成分与第一个主方正交,并且与第二个最大方差相关,依此类推。 对于二维数据集,此概念显示在以下屏幕截图中:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9Sv3Yv7O-1681652675145)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/b93e1305-0337-4224-b77d-22119c907841.png)]
二维数据集的主成分; 第一个主成分沿着方差最大的轴,而第二个主成分正交,并且与剩余方差成比例
至此,问题几乎解决了。 实际上,如果仅选择第一个k
主成分(v[i] ∈ R^(n×1)
),则可以构建一个变换矩阵A[k] ∈ R^(n×k)
,从而使特征向量与前k
个特征值列:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VLZwjt5g-1681652675145)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/25fc3f0b-9a46-4ae7-9ae1-e4fc48a72eda.png)]
因此,我们可以使用以下矩阵乘法来转换整个数据集:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tQXMNARv-1681652675145)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/b34ef798-1103-49d5-ab68-e75859ae3600.png)]
新数据集Z
的维数等于k < n
(或<<
),并且它包含与分量数量成比例的原始变化量。 例如,考虑上一个屏幕快照中显示的示例,如果我们选择单个分量,则所有向量都将沿着第一个主分量变换为点。 当然,会有一些信息丢失,必须逐案考虑; 在以下各节中,我们将讨论如何评估此类损失并做出合理的决定。 现在,我们将简要展示如何以有效方式提取主要成分。
具有奇异值分解的 PCA
即使我们将采用完整的 PCA 实现,了解如何有效地执行此过程也将有所帮助。 当然,最明显的处理方法是基于样本协方差矩阵的计算,其特征分解(将输出特征值和对应的特征向量),然后最后可以构建变换矩阵。 这种方法很简单,但不幸的是,它效率也不高。 主要原因是我们需要计算样本协方差矩阵,这对于大型数据集而言可能是一项非常长的任务。
奇异值分解(SVD)提供了一种更为有效的方法,它是一种线性代数程序,具有一些重要特征:它可以直接在数据集上操作,当提取了所需数量的组件时可以停止,并且有增量版本可以小批量工作,从而解决了内存不足的问题。 特别地,考虑到数据集X ∈ R^(m×n)
,SVD 可以表示为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LRN4yzfD-1681652675146)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/8c7d96e8-429e-41e8-b107-4f95d67c39c3.png)]
U
是一个正交矩阵(即UU^T = U^T U = I
,因此U^T = U^(-1)
),其中左手奇异向量作为行(XX^T
的特征向量);V
(也为正交)包含右手奇异向量作为行(对应于X^T X
的特征向量),而Λ
是一个对角矩阵,包含$1[$2]
的奇异值(这是XX^T
和X^T X
的特征值的平方根)。 特征值按降序排序,特征向量重新排列以匹配相应位置。 由于1 / m
因子是一个乘法常数,因此它不会影响特征值的相对大小; 因此,排序顺序保持不变。 因此,我们可以直接使用V
或U
进行工作,并从Λ
中选择第一个顶部k
特征值。 特别是,我们可以观察到以下结果(因为变换矩阵A
等于V
):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OHP6L0K8-1681652675146)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/2a969f33-17b7-4f4b-b322-238daea5f0e2.png)]
因此,通过使用U[k]
(仅包含顶部k
特征向量)和U[k]
](仅包含顶部的k
特征值),我们可以直接获得较低维的转换数据集(具有k
分量),如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rU4asaO1-1681652675146)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/6d9ea074-b25a-4353-8526-ec0675049126.png)]
此方法快速,有效,并且在数据集太大而无法放入内存时可以轻松扩展。 即使我们在本书中不使用此类场景,也值得一提的是 scikit-learn TruncatedSVD
类(其 SVD 限于k
最高特征值)和IncrementalPCA
类(小批量执行 PCA)。 为了我们的目的,我们将使用标准的PCA
类和一些重要的变体,它们要求整个数据集都适合内存。
白化
SVD 的一个重要应用是白化程序,该程序强制以空平均值(即E[X] = 0
)对数据集X
或零中心),以具有恒等式的协方差矩阵C
。 该方法对提高许多监督算法的表现非常有帮助,这可以受益于所有组件共享的统一单一方差。
将分解应用于C
,我们获得以下信息:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MSY19Fqj-1681652675146)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/29e02839-8777-46c9-a39f-f5c829986992.png)]
矩阵V
的列是C
的特征向量,而Λ
是包含特征值的对角矩阵(请记住,SVD 输出奇异值,它们是特征向量的平方根)。 因此,我们需要找到一个线性变换,z = Ax
,以便E[Z^T Z] = I
。 使用先前的分解时,这很简单:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pYnygpTi-1681652675146)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/523c33c0-9701-494f-9c60-8532278de6ab.png)]
从前面的方程式中,我们可以得出变换矩阵A
的表达式:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PknzN6Tl-1681652675147)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/2c719331-b8b9-4519-991b-8fc82bacea52.png)]
现在,我们将通过一个小的测试数据集展示美白效果,如下所示:
import numpy as np from sklearn.datasets import make_blobs X, _ = make_blobs(n_samples=300, centers=1, cluster_std=2.5, random_state=1000) print(np.cov(X.T))
前一个块的输出显示了数据集的协方差矩阵,如下所示:
[[6.37258226 0.40799363] [0.40799363 6.32083501]]
以下代码段显示了whiten()
函数,该函数用于对通用数据集进行美白(零居中是过程的一部分)(correct
参数在漂白之后强制执行缩放校正):
import numpy as np def zero_center(X): return X - np.mean(X, axis=0) def whiten(X, correct=True): Xc = zero_center(X) _, L, V = np.linalg.svd(Xc) W = np.dot(V.T, np.diag(1.0 / L)) return np.dot(Xc, W) * np.sqrt(X.shape[0]) if correct else 1.0
以下屏幕截图显示了应用于X
数组的增白结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1kuSFg8G-1681652675147)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/96f5814c-722a-4892-aecb-e31d1b885cc7.png)]
原始数据集(左); 白化的数据集(右)
现在,我们可以检查新的协方差矩阵,如下所示:
import numpy as np Xw = whiten(X) print(np.cov(Xw.T))
输出如下:
[[1.00334448e+00 1.78229783e-17] [1.78229783e-17 1.00334448e+00]]
可以看到,矩阵现在是一个恒等式(具有最小的误差),并且数据集也具有空均值。
具有 MNIST 数据集的 PCA
现在,让我们应用 PCA,以减少 MNIST 数据集的维数。 我们将使用 scikit-learn 提供的压缩版本(1,797,8×8 图像),但是我们的考虑都不会受到此选择的影响。 让我们从加载和规范化数据集开始:
from sklearn.datasets import load_digits digits = load_digits() X = digits['data'] / np.max(digits['data'])
从理论讨论中,我们知道协方差矩阵的特征值的大小与相应主成分的相对重要性(即,所解释的方差,因此是信息含量)成正比。 因此,如果将它们按降序排序,则可以计算以下差异:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9wcm7GFO-1681652675147)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/75540aa4-e15b-4bc0-8ffa-f81647e70fc7.png)]
当k → n
的数量变得越来越重要时,我们可以通过选择第一个最大的差值来选择最佳的k
,这表明所解释的数量大大减少了。 以下所有组件的差异。 为了更好地理解这种机制,让我们计算特征值和它们的差异(由于协方差矩阵C
是正半确定的,因此我们确定λ[i] ≥ 0, ∀i ∈ (1, n)
):
import numpy as np C = np.cov(X.T) l, v = np.linalg.eig(C) l = np.sort(l)[::-1] d = l[:l.shape[0]-1] - l[1:]
以下屏幕快照显示了展开图像(64 维数组)的差异:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZO18wUhi-1681652675147)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/8109d275-c6a0-42c6-b8cb-b7f2a22c590f.png)]
每个主成分的特征值差异
可以看出,第一主成分的差异非常大,与第四主成分(λ[4] - λ[3]
); 但是,下一个差异仍然很高,虽然对应$1[$2]
突然下降。 在这一点上,趋势几乎是稳定的(除了一些残余振荡),直到$1[$2]
为止,然后趋势开始迅速下降,趋于趋于零 。 由于我们仍然希望获得正方形图像,因此我们将选择k = 16
(相当于将每一边除以四)。 在另一个任务中,您可以选择k = 15
,甚至k = 8
; 但是,为了更好地理解降维导致的误差,也将有助于分析所解释的方差。 因此,让我们从执行 PCA 开始:
from sklearn.decomposition import PCA pca = PCA(n_components=16, random_state=1000) digits_pca = pca.fit_transform(X)
在拟合模型并将所有样本投影到对应于前 16 个主成分的子空间后,即可获得digits_pca
数组。 如果我们想将原始图像与其重构进行比较,则需要调用inverse_transform()
方法,该方法将投影投射到原始空间上。 因此,如果 PCA 在这种情况下是变换f(x): ℜ^64 → ℜ^16
,则逆变换为g(x): ℜ^16 → ℜ^64
。 以下屏幕截图显示了前 10 位数字与它们的重构之间的比较:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aJAVkIn5-1681652675147)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/6b57796e-5007-448a-9bd2-a96bc7e3affb.png)]
原始样本(第一行); 重建(底部行)
重建显然是有损的,但是数字仍然是可区分的。 现在,让我们通过对explained_variance_ratio_
数组的所有值求和来检查总的解释方差,其中包含每个分量的相对解释方差的相对数量(因此,任何k < n
分量始终小于 1):
print(np.sum(pca.explained_variance_ratio_))
上一个代码段的输出如下:
0.8493974642542452
因此,在将维数减少到 16 个分量的情况下,考虑到每个样本都将丢弃 48 个分量,我们正在解释原始差异的 85%,这是一个合理的值。
以下屏幕快照显示了显示所有单个贡献的图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VWPP6ZND-1681652675148)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/f34df112-3c13-4331-b106-31b3c662783d.png)]
对应每个主成分的解释方差比
正如预期的那样,贡献趋于减少,因为在这种情况下,第一个主要成分负责任; 例如,对于一种颜色的线条(例如黑色或白色),而其余的则为灰色。 这种行为非常普遍,几乎在每种情况下都可以观察到。 通过该图,还可以轻松找到额外的损失,以进一步减少损失。 例如,我们可以立即发现,对 3 个成分的严格限制可以解释原始差异的 40% ; 因此,剩余的 45% 被分为剩余的 13 个组成部分。 我邀请您重复此示例,尝试找出人类区分所有数字所需的最少数量的组件。
核 PCA
有时,数据集不是线性可分离的,并且标准 PCA 无法提取正确的主成分。 当我们面对非凸群集的问题时,该过程与第 3 章,“高级聚类”中讨论的过程没有什么不同。 在那种情况下,由于几何原因,某些算法无法执行成功的分离。 在这种情况下,目标是根据主成分的结构区分不同的类(在纯净,无监督的情况下,我们考虑特定的分组)。 因此,我们要使用转换后的数据集Z
,并检测可区分阈值的存在。 例如,让我们考虑以下屏幕截图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HMBnmn1o-1681652675148)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/1152710f-83cd-449a-9389-5540bb9ad014.png)]
原始数据集(左); PCA 投影版本(右)
由于原始数据集是线性可分离的,因此在 PCA 投影之后,我们可以立即找到允许检测第一个成分(这是真正需要的唯一成分)的阈值,以便区分两个斑点。 但是,如果数据集不是线性可分离的,我们将得到不可接受的结果,如以下屏幕截图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Pfc5jloH-1681652675148)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/d2439c67-b819-4557-9e0a-c50a1e0178b5.png)]
原始数据集(左); PCA 投影版本(右)
当几何形状更复杂时,找到可区分的阈值可能是不可能的。 但是,我们知道,将数据投影到高维空间可以使它们线性分离。 特别地,如果x ∈ ℜ^n
,我们可以选择适当的函数f(x)
,这样y = f(x) ∈ ℜ^p
,以及p >> n
。 不幸的是,将这种转换应用于整个数据集可能会非常昂贵。 实际上,给定一个转换矩阵A
(具有n
个组件),一个主分量,a(t)
投影后的可以编写如下(请记住它们是协方差矩阵的特征向量):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EREl4ubw-1681652675148)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/0b373061-285c-4f7a-aadc-13d1e235a978.png)]
因此,单个向量的转换如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DAsKPL81-1681652675148)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/febdde35-860f-4ead-b585-97c81169aa6a.png)]
可以看到,转换需要计算点积f(x[i])^T f(x[i])
。 在这些情况下,我们可以采用所谓的核技巧,该技巧指出存在称为核且具有有趣特性的特定函数K(·, ·)
,如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UkqM8Zzc-1681652675149)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/d4f72e86-05e8-4d2e-8030-cc028ce9c8c1.png)]
换句话说,我们可以通过仅计算每两个点的内核,而不是执行一个点积来计算在高维空间中的主成分上的投影,该点积在计算后需要n
乘法f(·)
的值。
一些常见的核如下:
- 径向基函数(RBF)或高斯核:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VaHhVd75-1681652675149)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/be7df07d-e755-4712-9b16-409ec45c4d9d.png)] p
为多项式核:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZAOt1Ci0-1681652675149)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/464465b9-c466-4538-8f60-33259f9424d7.png)]- Sigmoid 核:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ar89K12h-1681652675149)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/f1b5b271-2c9d-46d2-99c5-e00687a24f4c.png)]
对于非常大的数据集,该过程仍然相当昂贵(但是可以预先计算并存储内核值,以避免浪费额外的时间),但是它比标准投影更有效。 此外,其具有允许在可能进行线性辨别的空间中提取主要成分的优点。 现在,让我们将 RBF 核 PCA 应用于上一个屏幕快照中显示的半月数据集。 gamma
参数等于1 /σ^2
。 在这种特殊情况下,主要问题是存在双重重叠。 考虑到原始标准差约为 1.0(即σ^2 = 1
),我们至少需要三个标准差才能适当区分他们; 因此,我们将设置γ = 10
:
from sklearn.datasets import make_moons from sklearn.decomposition import KernelPCA X, Y = make_moons(n_samples=800, noise=0.05, random_state=1000) kpca = KernelPCA(n_components=2, kernel='rbf', gamma=10.0, random_state=1000) X_pca = kpca.fit_transform(X)
投影结果显示在以下屏幕截图中:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JvNXlyIW-1681652675149)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/2f600a98-54fb-439c-8be8-898b4650d05c.png)]
原始数据集(左);核 PCA 投影版本(右)
可以看到,即使在这种情况下,第一个分量也足以做出决定(由于噪声,公差最小),将阈值设置为零可以分离数据集。 我邀请读者测试其他内核的效果并应用它们,以区分包含所有零和一的 MNIST 子集。
通过因子分析为异方差噪声添加更多鲁棒性
标准 PCA 的主要问题之一是这种模型在异方差噪声方面的固有弱点。 如果您不熟悉此术语,则引入两个定义将很有帮助。 多元去相关噪声项的特征在于对角协方差矩阵C
,该矩阵可以具有两种不同的配置,如下所示:
C = diag(σ^2, σ^2, ..., σ^2)
:在这种情况下,噪声定义为同调(所有分量均具有相同的方差)。C = diag(σ[1]^2, σ[2]^2, ..., σ[n]^2)
,其中σ[1]^2 ≠ σ[2]^2 ≠ ... ≠σ[n]^2
:在这种情况下,噪声定义为异方差(每个分量都有其自身的方差)。
有可能证明,当噪声是同调的时,PCA 可以轻松地对其进行管理,因为单个分量的解释方差以相同的方式受噪声项的影响(也就是说,这等同于不存在噪声)。 相反,当噪声为异方差时,PCA 的表现将下降,其结果可能绝对不可接受。 因此,Rubin 和 Thayer(在《用于 ML 因子分析的 EM 算法》中)提出了另一种降维方法,称为因子分析,它可以解决此类问题。
假设我们有一个零中心数据集X
,其中包含m
个样本x[i] ∈ ℜ^n
。 我们的目标是找到一组潜在变量,z[i] ∈ ℜ^p
(其中p < n
)和矩阵A
(称为因子加载矩阵),以便可以重写每个样本,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SmRzfxPW-1681652675150)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/f30e647b-5fcb-4fb0-a0fc-26e5698a673d.png)]
因此,我们现在假设样本x[i]
是一组高斯潜变量加上一个额外的异方差噪声项的组合。 由于潜在变量的维数较低,因此问题与标准 PCA 非常相似,主要区别在于,我们现在考虑了异方差噪声(当然,n
项也可以为null
,或者同调)。 因此,当确定分量(即潜在变量)时,模型中将包括不同噪声方差的影响,最终效果是部分滤波(降噪)。 在上述论文中,作者提出了一种优化算法,该算法形式上不是很复杂,但是需要许多数学操作(因此,我们省略了任何证明)。 此方法基于期望最大化(EM)算法,该算法有助于查找使对数似然性最大化的参数集。 在本书中,我们无需讨论所有数学细节(可在原始论文中找到),而是检查该方法的属性并将结果与标准 PCA 进行比较。
让我们首先加载 Olivetti 人脸数据集,将其零居中,然后创建一个异方差嘈杂的版本,如下所示:
import numpy as np from sklearn.datasets import fetch_olivetti_faces faces = fetch_olivetti_faces(shuffle=True, random_state=1000) X = faces['data'] Xz = X - np.mean(X, axis=0) C = np.diag(np.random.uniform(0.0, 0.1, size=Xz.shape[1])) Xnz = Xz + np.random.multivariate_normal(np.zeros(shape=Xz.shape[1]), C, size=Xz.shape[0])
以下屏幕截图显示了一些原始图像和嘈杂图像:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DRWSVvIb-1681652675150)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/6ceb7a52-0d18-4da0-9da0-a94f57f47c6e.png)]
原始图像(上一行); 嘈杂的版本(下一行)
现在,让我们评估以下各项的平均对数似然率(通过score()
方法,PCA
和FactorAnalysis
类均可用的):
- PCA,具有原始数据集和
128
组件 - PCA,带有嘈杂的数据集和
128
组件 - 因子分析,带有嘈杂的数据集和
128
分量(潜在变量)
在以下代码段中,所有 3 个模型都被实例化和训练:
from sklearn.decomposition import PCA, FactorAnalysis pca = PCA(n_components=128, random_state=1000) pca.fit(Xz) print('PCA log-likelihood(Xz): {}'.format(pca.score(Xz))) pcan = PCA(n_components=128, random_state=1000) pcan.fit(Xnz) print('PCA log-likelihood(Xnz): {}'.format(pcan.score(Xnz))) fa = FactorAnalysis(n_components=128, random_state=1000) fa.fit(Xnz) print('Factor Analysis log-likelihood(Xnz): {}'.format(fa.score(Xnz)))
上一个代码段的输出如下:
PCA log-likelihood(Xz): 4657.3828125 PCA log-likelihood(Xnz): -2426.302304948351 Factor Analysis log-likelihood(Xnz): 1459.2912218162423
这些结果表明存在异方差噪声时因素分析的有效性。 PCA 实现的最大平均对数似然度约为4657
,在存在噪声的情况下降至-2426
。 相反,因子分析获得的平均对数似然率约为 1,460,这比使用 PCA 获得的对数似然率大得多(即使尚未完全滤除噪声的影响)。 因此,每当数据集包含(或数据科学家怀疑包含)异方差噪声时(例如,样本是作为不同仪器捕获的源的叠加而获得的),我强烈建议将因子分析作为主要的降维方法。 当然,如果要求其他条件(例如,非线性,稀疏性等),则可以在做出最终决定之前评估本章中讨论的其他方法。
稀疏的 PCA 和字典学习
标准 PCA 通常是密集分解; 这就是说,向量一旦转换,便是所有具有非零系数的分量的线性组合:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NFc40Gy8-1681652675150)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/6d321ec9-2ff5-4b21-8c88-e47d435bf51a.png)]
在前面的表达式中,系数$1[$2]
几乎总是不为零,因此所有组件都参与重建过程。 出于降维的目的,这不是问题,因为为了限制它们,我们对每个组件解释的方差更感兴趣。 但是,在某些任务下,分析每个较大的构建原子很有帮助,并假设每个向量都可以表示为它们的稀疏组合。 最经典的例子是文本语料库,其中词典包含的项目比每个文档中涉及的项目更多。 这些类型的模型通常称为字典学习算法,因为原子集定义了一种字典,其中包含可用于创建新样本的所有单词。 当原子数k
大于样本的维数n
时,该字典被称为过度完成,其表示通常是稀疏的。 相反,当k < n
时,字典被称为尚未完成,并且向量需要更密集。
通过对函数的最小化,对解决方案的L[1]
范数施加惩罚,可以轻松解决此类学习问题。 这种限制导致稀疏性的原因不在本书的讨论范围之内,但是有兴趣的人可以在《Mastering Machine Learning Algorithms》中找到更长的讨论范围。
字典学习(以及稀疏 PCA)的问题可以正式表示为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qs55gP0X-1681652675150)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/b671cd38-0abc-483b-bf3d-80dfa23c6a65.png)]
这是一种算法的特殊情况,其中U[k]
的分量被强制具有单位长度(除非normalize_components=False
参数) ,并对系数V
进行了惩罚,以增加其稀疏度(与系数α
成比例)。
让我们考虑 MNIST 数据集,它执行具有 30 个成分的稀疏 PCA(产生不完全的字典)和中高稀疏度(例如α = 2.0
)。 数组X
应该包含归一化的样本,并在以下 PCA 示例中显示:
from sklearn.decomposition import SparsePCA spca = SparsePCA(n_components=30, alpha=2.0, normalize_components=True, random_state=1000) spca.fit(X)
在训练过程结束时,components_
数组包含原子,如以下屏幕快照所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yGeTzHJq-1681652675151)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/da76643e-d124-44d4-8547-a59042c1190b.png)]
稀疏 PCA 算法提取的成分
不难理解,每个数字都可以由这些原子组成。 但是,考虑到原子数,稀疏度不能非常大。 例如,考虑数字X[0]
的转换:
y = spca.transform(X[0].reshape(1, -1)).squeeze()
以下屏幕快照显示了系数的绝对值:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DIHsVP8O-1681652675151)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/b9997b84-83e2-4bf5-a810-a95a8d0191d1.png)]
X[0]
的稀疏转换的绝对系数
显然有一些主要成分(例如 2,7,13,17,21,24,26,27 和 30 ),一些次要的(例如 5,8 等)和一些无效或可忽略的值(例如 1,3,6 等)。 如果以相同的代码长度(30 个分量)增加稀疏度,则对应于空分量的系数将降至零,而如果代码长度也增加(例如k = 100
) ,字典将变得过于完整,并且空系数的数量也将增加。
非负矩阵分解
当数据集X
为非负数时,可以应用已被证明的分解技术(例如,在《通过非负矩阵分解学习对象的部分》中)在任务目标是提取与样本结构部分相对应的原子时更加可靠。 例如,在图像的情况下,它们应该是几何元素,甚至是更复杂的部分。 非负矩阵分解(NNMF)施加的主要条件是,所有涉及的矩阵都必须为非负,并且X = UV
。 因此,一旦定义了标准N
(例如 Frobenius),则简单目标就变成了:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tYjmUTmx-1681652675151)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/f554b0eb-d763-49ca-a7c2-6916ff5e9523.png)]
由于这在通常还需要稀疏性的情况下通常是不可接受的(而且,为了在更改解决方案以满足特定要求时具有更大的灵活性),因此通常通过在两个 Frobenius 上加点惩罚来表达该问题(例如在 scikit-learn 中) (L[2]
的矩阵扩展)和L[1]
规范(例如,在 ElasticNet 中):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-opj5m4Sc-1681652675151)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/b12f42f8-c6ae-4a84-b399-061168e10d1c.png)]
双重正则化通过避免类似于监督模型的过拟合的效果,使您既可以获得稀疏性,又可以获得样本的各部分之间的更好匹配(由于该解决方案次优,因此在适应新模型时更加灵活) 样本是从相同的数据生成过程中提取的;这增加了通常可以实现的可能性)。
现在,让我们考虑 MNIST 数据集,并将其分解为 50 个原子,最初设置α = 2.0
和β = 0.1
(在 scikit-learn 中称为l1_ratio
)。 此配置将强制中等稀疏性和强 L2/Frobenius 正则化。 该过程非常简单,类似于稀疏 PCA:
from sklearn.decomposition import NMF nmf = NMF(n_components=50, alpha=2.0, l1_ratio=0.1, random_state=1000) nmf.fit(X)
在训练过程结束时,组件(原子)如以下屏幕快照所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kHAVkrTC-1681652675151)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/fc28caef-8e14-4593-a2dc-6162aaed6ed5.png)]
NNMF 算法提取的原子
与我们在标准字典学习中观察到的相反,原子现在结构化了很多,并且它们再现了数字的特定部分(例如,垂直或水平笔画,圆,点等); 因此,我们可以预期会有更多的稀疏表示,因为更少的组件足以构成一个数字。 考虑上一节中显示的示例(数字X[0]
),所有组件的绝对贡献如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uVhliJYi-1681652675152)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/9cea1dd3-7125-426d-adf4-3a4801c7d2a4.png)]
X[0]
的 NNMF 的绝对系数
占主导地位的是三个部分( 3 , 24 和 45 ); 因此,我们可以尝试将样本表示为它们的组合。 系数分别为 0.19、0.18 和 0.16。 结果显示在以下屏幕截图中(数字X[0]
代表零):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oOv9DHG0-1681652675152)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/b7dc5e46-5859-49af-be9f-87b09a6bf01a.png)]
基于三个主成分来解构数字X[0]
有趣的是,该算法是如何选择原子的。 即使此过程受到α
和β
参数,以及规范的强烈影响,我们也可以观察到,例如,第三个原子( 屏幕截图中的第一个)可以被许多零,三和八共享; 最后一个原子对于零和九都是有帮助的。 每当原子的粒度太粗糙时,具有较弱的L[1]
罚分的不完整字典可能会有所帮助。 当然,每个问题都需要特定的解决方案。 因此,我强烈建议与领域专家一起检查原子的结构。 作为练习,我邀请您将 NNMF 应用于另一个小图像数据集(例如 Olivetti,Cifar-10 或 STL-10),并尝试找到隔离固定数量的结构零件所必需的正确参数( 例如,对于人脸,它们可以是眼睛,鼻子和嘴巴。
独立成分分析
当使用标准 PCA(或其他技术,例如因子分析)时,组件是不相关的,但是不能保证它们在统计上是独立的。 换句话说,假设我们有一个数据集X
,它是从联合概率分布p(X)
中得出的; 如果n
个组件存在,我们不能总是确定以下等式成立:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FouuufP3-1681652675152)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/3b056214-1a06-43b5-97cd-0c1ee2e42303.png)]
但是,基于称为鸡尾酒会的通用模型,有许多重要任务。 在这种情况下,我们可以假设(或我们知道)许多不同且独立的源(例如声音和音乐)重叠并生成单个信号。 在这一点上,我们的目标是尝试通过对每个样本进行线性变换来分离源。 让我们考虑一个增白的数据集X
(因此所有组件都具有相同的信息内容),我们可以假定是从高斯分布N(0, I)
中采样的( 这不是限制性条件,因为许多不同源的重叠很容易收敛到正态分布。 因此,目标可以表示如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jb92hzgg-1681652675152)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/ec86cdcc-2bc6-49b3-9bf8-1517b0a6ce34.png)]
换句话说,我们将每个样本表示为许多独立因素的乘积,并具有基于指数函数的先验分布。 必须绝对强制执行的唯一条件是非高斯性(否则,各组成部分将变得难以区分)。 因此,函数f[k](z)
不能为二次多项式。 在实践中,我们还希望包括中等程度的稀疏性,因此我们期望出现峰值和重尾分布(也就是说,概率仅在非常短的范围内才很高,然后突然下降到几乎为零)。 这种情况可以通过检查归一化的第四矩峰度来验证:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mQj0YMWy-1681652675152)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/56c4514e-1b79-48f0-92ed-c4b0596ede4c.png)]
对于高斯分布,峰度为 3。由于这通常是一个参考值,因此所有具有Kurtosis(X) > 3
的分布都称为超高斯或尖峰。 ,将具有Kurtosis(X) < 3
的人称为亚高斯性或平峰。 前一个分配类别的示例是 Laplace 分配类别,如以下屏幕截图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TUNIwWLH-1681652675153)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/fd260b15-bd75-4638-8be4-1f69c6c4d9a5.png)]
高斯分布(左)和拉普拉斯分布(右)的概率密度函数
不幸的是,峰度的使用由于其对异常值的缺乏鲁棒性而受到阻碍(也就是说,由于它涉及四次方,因此即使很小的值也可以被放大并改变最终结果;例如,噪声高斯的尾部的离群值可以显示为超高斯)。 因此,作者 Hyvarinen 和 Oja (在《独立组件分析:算法和应用》中)提出了一种称为快速独立组件分析(FastICA)基于负熵的概念。 我们不会在本书中描述整个模型。 但是,了解基本思想会有所帮助。 可以证明,在具有相同方差的所有分布之间,高斯熵最大。 因此,如果数据集X
(零中心)已从具有协方差Σ
的分布中得出,则可以定义X
作为高斯N(0 ;Σ)
的熵与X
的熵之间的差
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g51WrFWl-1681652675153)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/c69596e4-c1c9-4843-8a54-eaf1e7682f29.png)]
因此,我们的目标是通过减少J(X)
来减少H[N](X)
(始终大于或等于零)。 FastICA 算法基于特定特征的组合,近似于H[N](X)
。 最常见的称为 logcosh (它也是 scikit-learn 中的默认值),如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HbY0QPlD-1681652675153)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/f733002f-7004-42d5-9f94-42f5be45dfd4.png)]
使用此技巧,可以更轻松地优化负熵,并且最终分解必定包含独立的成分。 现在,让我们将 FastICA 算法应用于 MNIST 数据集(为了提高精度,我们设置max_iter=10000
和tol=1e-5
):
from sklearn.decomposition import FastICA ica = FastICA(n_components=50, max_iter=10000, tol=1e-5, random_state=1000) ica.fit(X)
以下屏幕快照显示了该算法找到的 50 个独立组件(始终通过components_
i 实例变量可用)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2taDFvIZ-1681652675153)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/b7ee2fce-1609-4c31-aad4-e654090162b8.png)]
FastICA 提取的独立成分
在这种情况下,组件可以立即被识别为数字的一部分(考虑到数据集的维数,我邀请读者通过减少和增加组件的数量直至 64(这是最大数量)来重复该示例)。 这些分量趋于到达相应分布的平均位置。 因此,使用较少的数量,就可以区分出更多的结构化模式(可以视为不同的重叠信号),而使用更多的组件,则可以得到更多以特征为中心的元素。 但是,与 NNMF 相反,FastICA 不保证提取样本的实际部分,而是保证提取更完整的区域。 换句话说,尽管 NNMF 可以轻松检测到例如某些单个笔触,但 FastICA 倾向于将样本视为不同信号的总和,在图像的情况下,通常涉及样本的整个维数,除非组件数量急剧增加。 为了更好地理解这个概念,让我们考虑一下 Olivetti 人脸数据集,其中包含 400 张 64×64 灰度肖像:
from sklearn.datasets import fetch_olivetti_faces faces = fetch_olivetti_faces(shuffle=True, random_state=1000)
以下屏幕截图显示了前 10 张面孔:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bFoAqhb8-1681652675154)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/b3216550-d65a-49d5-bbe3-902737f9ca8a.png)]
从 Olivetti 人脸数据集中提取的人脸样本
现在,让我们提取 100 个独立的组件:
ica = FastICA(n_components=100, max_iter=10000, tol=1e-5, random_state=1000) ica.fit(faces['data'])
下面的屏幕截图绘制了前 50 个组件:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Rk4f8e8h-1681652675154)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/b70d1a5f-69b2-4c53-8dd1-1a48899153f2.png)]
50 (out of 100) independent components extracted by FastICA
如您所见,每个组成部分都类似于元人脸(有时称为特征人脸),由于所有其余部分(即使它们无法在精确的样本集中立即识别出来)。 当组件的数量增加到 350 时,效果将更加明显,如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RiFrbN5F-1681652675154)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/handson-unsup-learn-py/img/59bedc09-a9d7-4314-8e2b-85d92e82d73f.png)]
50 (out of 350) independent components extracted by FastICA
在这种情况下,次要特征不太占优势,因为存在更多的重叠分布,并且每个特征都集中在一个更原子的本征面上。 当然,如果没有完整的领域知识,就无法定义组件的最佳数量。 例如,对于 Olivetti 人脸数据集,识别特定的子元素(例如,眼镜的位置)或更完整的人脸表情可能会有所帮助。 在前一种情况下,更多的组件会产生更集中的解决方案(即使它们在全局范围内的区别性较小),而在后一种情况下,数量较少的组件(例如上一个示例)会产生更完整的结果,可以评估不同的影响因素。 就信号而言,组件的数量应等于预期的重叠因子的数量(假设其独立性)。 例如,音频信号可以包含在机场讲话的人的录音,并带有宣布飞行的背景声音。 在这种情况下,方案可以由三个部分组成:两个声音和噪音。 由于噪声将部分分解为主要成分,因此最终数量将等于 2。