半监督学习是指试图同时利用有标签和无标签训练数据的算法。
半监督学习算法与仅能从有标签训练数据中学习的有监督学习算法不同。
半监督学习的一种流行方法是创建一个图,该图连接训练数据集中的样本,并通过图的边传播已知标签,为无标签样本分配标签。这种半监督学习方法的一个例子是用于分类预测建模的标签传播算法。
在本教程中,您将了解如何将标签传播算法应用于半监督学习分类数据集。
完成本教程后,您将了解:
- 了解标签传播半监督学习算法的工作原理。
- 如何开发半监督分类数据集并通过有监督学习算法建立性能基线。
- 如何开发和评估标签传播算法,并使用模型输出来训练有监督学习算法。
让我们开始吧。

使用标签扩散的半监督学习
照片来自 Jernej Furman,部分权利保留。
教程概述
本教程分为三个部分;它们是:
- 标签传播算法
- 半监督分类数据集
- 用于半监督学习的标签传播
标签传播算法
标签传播是一种半监督学习算法。
该算法由 Dengyong Zhou 等人于 2003 年在其论文“Learning With Local And Global Consistency”中提出。
半监督学习的更广泛方法的基本思想是,输入空间中附近的点应该具有相同的标签,并且在输入空间中具有相同结构或流形的点应该具有相同的标签。
半监督学习问题的关键在于一致性的先验假设,这意味着:(1) 附近的点可能具有相同的标签;以及 (2) 位于相同结构(通常称为簇或流形)的点可能具有相同的标签。
— 《Learning With Local And Global Consistency》,2003。
标签传播受到实验心理学中一种称为传播激活网络的技术的启发。
该算法可以从实验心理学的传播激活网络的角度来直观理解。
— 《Learning With Local And Global Consistency》,2003。
数据集中的点根据它们在输入空间中的相对距离在图中连接。图的权重矩阵被对称地归一化,这与 谱聚类 非常相似。信息通过图进行传递,该图被调整以捕获输入空间中的结构。
这种方法与用于半监督学习的标签传播算法非常相似。
Zhou 等人给出了另一种类似的标签传播算法:在每一步,节点 i 接收来自其邻居 j 的贡献(由边 (i,j) 的归一化权重加权),以及由其初始值给出的额外少量贡献。
— 第 196 页,《Semi-Supervised Learning》,2006。
收敛后,标签根据传递信息最多的节点进行分配。
最后,每个未标记点的标签设置为在迭代过程中接收信息最多的类的类别。
— 《Learning With Local And Global Consistency》,2003。
现在我们熟悉了标签传播算法,让我们看看如何在项目中使用它。首先,我们必须定义一个半监督学习数据集。
半监督分类数据集
在本节中,我们将为半监督学习定义一个数据集,并在此数据集上建立性能基线。
首先,我们可以使用 make_classification() 函数 定义一个合成分类数据集。
我们将定义一个具有两个类别(二元分类)、两个输入变量和 1,000 个样本的数据集。
1 2 3 |
... # 定义数据集 X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, random_state=1) |
接下来,我们将数据集分为训练集和测试集,比例为 50-50(例如,每个 500 行)。
1 2 3 |
... # 分割成训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50, random_state=1, stratify=y) |
最后,我们将训练数据集再次分成两半,一部分有标签,一部分我们假装是无标签的。
1 2 3 |
... # 将训练集分为有标签和无标签 X_train_lab, X_test_unlab, y_train_lab, y_test_unlab = train_test_split(X_train, y_train, test_size=0.50, random_state=1, stratify=y_train) |
总而言之,准备半监督学习数据集的完整示例列在下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 准备半监督学习数据集 from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split # 定义数据集 X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, random_state=1) # 分割成训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50, random_state=1, stratify=y) # 将训练集分为有标签和无标签 X_train_lab, X_test_unlab, y_train_lab, y_test_unlab = train_test_split(X_train, y_train, test_size=0.50, random_state=1, stratify=y_train) # 总结训练集大小 print('有标签训练集:', X_train_lab.shape, y_train_lab.shape) print('无标签训练集:', X_test_unlab.shape, y_test_unlab.shape) # 总结测试集大小 print('测试集:', X_test.shape, y_test.shape) |
运行示例将准备数据集,然后总结这三部分的大小。
结果证实我们有一个包含 500 行的测试数据集、一个包含 250 行的有标签训练数据集以及 250 行的无标签数据。
1 2 3 |
有标签训练集: (250, 2) (250,) 无标签训练集: (250, 2) (250,) 测试集: (500, 2) (500,) |
有监督学习算法只能从 250 行中训练模型。
半监督学习算法将拥有 250 个有标签行以及 250 个无标签行,这些无标签行可以通过多种方式用于改进有标签训练数据集。
接下来,我们可以使用仅在有标签训练数据上拟合的有监督学习算法,为半监督学习数据集建立性能基线。
这很重要,因为我们期望半监督学习算法的性能优于仅在有标签数据上拟合的有监督学习算法。如果不是这样,那么半监督学习算法就没有什么优势。
在本例中,我们将使用在有标签训练数据集部分拟合的逻辑回归算法。
1 2 3 4 5 |
... # 定义模型 model = LogisticRegression() # 在有标签数据集上拟合模型 model.fit(X_train_lab, y_train_lab) |
然后可以使用该模型对整个留出测试数据集进行预测,并使用分类准确率对其进行评估。
1 2 3 4 5 6 7 |
... # 对留出测试集进行预测 yhat = model.predict(X_test) # 计算测试集的得分 score = accuracy_score(y_test, yhat) # 总结得分 print('准确率: %.3f' % (score*100)) |
总而言之,在半监督学习数据集上评估有监督学习算法的完整示例列在下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 在半监督学习数据集上的基线性能 from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score 从 sklearn.线性模型 导入 LogisticRegression # 定义数据集 X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, random_state=1) # 分割成训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50, random_state=1, stratify=y) # 将训练集分为有标签和无标签 X_train_lab, X_test_unlab, y_train_lab, y_test_unlab = train_test_split(X_train, y_train, test_size=0.50, random_state=1, stratify=y_train) # 定义模型 model = LogisticRegression() # 在有标签数据集上拟合模型 model.fit(X_train_lab, y_train_lab) # 对留出测试集进行预测 yhat = model.predict(X_test) # 计算测试集的得分 score = accuracy_score(y_test, yhat) # 总结得分 print('准确率: %.3f' % (score*100)) |
运行算法将模型拟合到有标签训练数据集,并在留出数据集上进行评估,并打印分类准确率。
注意:您的 结果可能因算法或评估程序的随机性,或数值精度的差异而有所不同。考虑多次运行示例并比较平均结果。
在这种情况下,我们可以看到该算法实现了约 84.8% 的分类准确率。
我们期望有效的半监督学习算法的准确率会高于此。
1 |
准确率: 84.800 |
接下来,让我们探讨如何将标签传播算法应用于数据集。
用于半监督学习的标签传播
标签传播算法可通过 scikit-learn Python 机器学习库中的 LabelSpreading 类获得。
该模型可以像任何其他分类模型一样,通过调用 fit() 函数进行拟合,并通过 predict() 函数用于对新数据进行预测。
1 2 3 4 5 6 7 |
... # 定义模型 model = LabelSpreading() # 在训练数据集上拟合模型 model.fit(..., ...) # 对留出测试集进行预测 yhat = model.predict(...) |
重要的是,提供给 fit() 函数的训练数据集必须包含序数编码(如常态)的有标签样本和标记为 -1 标签的无标签样本。
模型将在拟合模型的过程中为无标签样本确定一个标签。
模型拟合后,训练数据集中有标签和无标签数据的估计标签可通过 LabelSpreading 类的 “transduction_” 属性获得。
1 2 3 |
... # 获取整个训练数据集数据的标签 tran_labels = model.transduction_ |
现在我们熟悉了如何在 scikit-learn 中使用标签传播算法,让我们看看如何将其应用于我们的半监督学习数据集。
首先,我们必须准备训练数据集。
我们可以将训练数据集的输入数据连接成一个数组。
1 2 3 |
... # 创建训练数据集输入 X_train_mixed = concatenate((X_train_lab, X_test_unlab)) |
然后,我们可以为无标签训练数据集中的每一行创建一个包含 -1 值的列表(无标签)。
1 2 3 |
... # 为无标签数据创建“无标签” nolabel = [-1 for _ in range(len(y_test_unlab))] |
然后可以将此列表与来自有标签训练数据集部分的标签连接起来,以对应训练数据集的输入数组。
1 2 3 |
... # 重组训练数据集标签 y_train_mixed = concatenate((y_train_lab, nolabel)) |
我们现在可以在整个训练数据集上训练 LabelSpreading 模型。
1 2 3 4 5 |
... # 定义模型 model = LabelSpreading() # 在训练数据集上拟合模型 model.fit(X_train_mixed, y_train_mixed) |
接下来,我们可以使用该模型对留出数据集进行预测,并使用分类准确率来评估模型。
1 2 3 4 5 6 7 |
... # 对留出测试集进行预测 yhat = model.predict(X_test) # 计算测试集的得分 score = accuracy_score(y_test, yhat) # 总结得分 print('准确率: %.3f' % (score*100)) |
总而言之,在半监督学习数据集上评估标签传播的完整示例列在下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# 在半监督学习数据集上评估标签传播 from numpy import concatenate from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score from sklearn.semi_supervised import LabelSpreading # 定义数据集 X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, random_state=1) # 分割成训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50, random_state=1, stratify=y) # 将训练集分为有标签和无标签 X_train_lab, X_test_unlab, y_train_lab, y_test_unlab = train_test_split(X_train, y_train, test_size=0.50, random_state=1, stratify=y_train) # 创建训练数据集输入 X_train_mixed = concatenate((X_train_lab, X_test_unlab)) # 为无标签数据创建“无标签” nolabel = [-1 for _ in range(len(y_test_unlab))] # 重组训练数据集标签 y_train_mixed = concatenate((y_train_lab, nolabel)) # 定义模型 model = LabelSpreading() # 在训练数据集上拟合模型 model.fit(X_train_mixed, y_train_mixed) # 对留出测试集进行预测 yhat = model.predict(X_test) # 计算测试集的得分 score = accuracy_score(y_test, yhat) # 总结得分 print('准确率: %.3f' % (score*100)) |
运行算法将模型拟合到整个训练数据集,然后在留出数据集上进行评估,并打印分类准确率。
注意:您的 结果可能因算法或评估程序的随机性,或数值精度的差异而有所不同。考虑多次运行示例并比较平均结果。
在这种情况下,我们可以看到标签传播模型实现了约 85.4% 的分类准确率,这略高于仅在有标签训练数据集上拟合的逻辑回归,后者的准确率约为 84.8%。
1 |
准确率: 85.400 |
到目前为止进展顺利。
我们可以与半监督模型使用的另一种方法是,获取训练数据集的估计标签,然后拟合一个有监督学习模型。
回想一下,我们可以如下从标签传播模型中检索整个训练数据集的标签。
1 2 3 |
... # 获取整个训练数据集数据的标签 tran_labels = model.transduction_ |
然后,我们可以使用这些标签以及所有输入数据来训练和评估有监督学习算法,例如逻辑回归模型。
希望的是,在整个训练数据集上拟合的有监督学习模型将比单独的半监督学习算法取得更好的性能。
1 2 3 4 5 6 7 8 9 10 11 |
... # 定义有监督学习模型 model2 = LogisticRegression() # 在整个训练数据集上拟合有监督学习模型 model2.fit(X_train_mixed, tran_labels) # 对留出测试集进行预测 yhat = model2.predict(X_test) # 计算测试集的得分 score = accuracy_score(y_test, yhat) # 总结得分 print('准确率: %.3f' % (score*100)) |
总而言之,使用估计的训练集标签来训练和评估有监督学习模型的完整示例列在下面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# 使用标签传播对半监督学习进行逻辑回归拟合评估 from numpy import concatenate from sklearn.datasets import make_classification from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score from sklearn.semi_supervised import LabelSpreading 从 sklearn.线性模型 导入 LogisticRegression # 定义数据集 X, y = make_classification(n_samples=1000, n_features=2, n_informative=2, n_redundant=0, random_state=1) # 分割成训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.50, random_state=1, stratify=y) # 将训练集分为有标签和无标签 X_train_lab, X_test_unlab, y_train_lab, y_test_unlab = train_test_split(X_train, y_train, test_size=0.50, random_state=1, stratify=y_train) # 创建训练数据集输入 X_train_mixed = concatenate((X_train_lab, X_test_unlab)) # 为无标签数据创建“无标签” nolabel = [-1 for _ in range(len(y_test_unlab))] # 重组训练数据集标签 y_train_mixed = concatenate((y_train_lab, nolabel)) # 定义模型 model = LabelSpreading() # 在训练数据集上拟合模型 model.fit(X_train_mixed, y_train_mixed) # 获取整个训练数据集数据的标签 tran_labels = model.transduction_ # 定义有监督学习模型 model2 = LogisticRegression() # 在整个训练数据集上拟合有监督学习模型 model2.fit(X_train_mixed, tran_labels) # 对留出测试集进行预测 yhat = model2.predict(X_test) # 计算测试集的得分 score = accuracy_score(y_test, yhat) # 总结得分 print('准确率: %.3f' % (score*100)) |
运行算法将半监督模型拟合到整个训练数据集,然后使用推断标签将有监督学习模型拟合到整个训练数据集,并在留出数据集上进行评估,打印分类准确率。
注意:您的 结果可能因算法或评估程序的随机性,或数值精度的差异而有所不同。考虑多次运行示例并比较平均结果。
在这种情况下,我们可以看到这种半监督模型后跟有监督模型的层次化方法在留出数据集上实现了约 85.8% 的分类准确率,略优于单独使用的半监督学习算法,后者的准确率约为 85.6%。
1 |
准确率: 85.800 |
您可以通过调整 LabelSpreading 模型的超参数来获得更好的结果吗?
请在下面的评论中告诉我您的发现。
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
书籍
- 半监督学习导论, 2009.
- 第 11 章:标签传播与二次准则,《Semi-Supervised Learning》,2006。
论文
- 具有局部和全局一致性的学习, 2003.
API
- sklearn.semi_supervised.LabelSpreading API.
- 第 1.14 节。半监督学习,Scikit-Learn 用户指南.
- sklearn.model_selection.train_test_split API.
- sklearn.linear_model.LogisticRegression API.
- sklearn.datasets.make_classification API.
文章
总结
在本教程中,您了解了如何将标签传播算法应用于半监督学习分类数据集。
具体来说,你学到了:
- 了解标签传播半监督学习算法的工作原理。
- 如何开发半监督分类数据集并通过有监督学习算法建立性能基线。
- 如何开发和评估标签传播算法,并使用模型输出来训练有监督学习算法。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
嗨,Jason,
一如既往的好文章。
标签传播是否对类别不平衡敏感,是否主要传播过表示的类别?
如果是,是否有办法应对,例如给予附近少数类别样本更多权重?
谢谢。
我预计该技术对类别不平衡敏感,并假设一个平衡的训练集。也许可以查阅文献以确认,并检查是否有方法相应地调整标签传播算法。
你好 Jason,
我对 PCA 有几个问题。
PCA(n_components=2) 是否意味着结果是一个包含两列的数据集?
在下面的示例中,分类器(逻辑回归)在 standardscaler 之后是否只使用两列?
>>> pipe_lr = make_pipeline(StandardScaler(),
PCA(n_components=2), LogisticRegression(random_state=1, solver=’lbfgs’)
PCA 是否也适用于分类和回归?
谢谢,
Marco
是的,在转换数据集后它将选择 2 个分量 – 例如,结果是 2 列。
是的,该转换可用于分类和回归预测任务。
Jason,
有没有一个经验法则来选择 PCA 相对于 LDA?何时使用它们?
您是否有简单的例子来解释 PCA 和 LDA?
谢谢,
Marco
没有,请仔细实验并选择能为您的特定数据集带来最佳性能的技术。
你好 Jason,
一个关于 PCA 的问题。
混合使用 sklearn 和 keras 有意义吗?
我的意思是先应用 StandardScaler(),然后是 PCA(例如 n_components=2)
然后将输出作为神经网络(如 MLP)的输入?
谢谢,
Marco
是的,sklearn 中的数据预处理非常有帮助。
Jason,
如何决定 PCA 的组件数量,例如 (n_components=2)。
有没有办法?
特征重要性分析是否有帮助?
谢谢,
Marco
尝试一系列值并进行比较,请参见此处获取示例
https://machinelearning.org.cn/principal-components-analysis-for-dimensionality-reduction-in-python/
对于我来说,这是一篇非常有信息量的帖子,因为这是我第一次学习半监督学习。
谢谢。
在用于半监督学习的标签传播中,为什么我们将 X_test_unlab 用作训练的一部分?
半监督学习意味着我们有大量的无标签数据。
半监督学习算法可以利用这些无标签数据。
Tornado 是一个帮助您执行半监督学习的无代码工具,更多详情可以在此处找到:https://www.linkedin.com/pulse/tornado-zero-coding-active-learning-ml-tool-walid-daboubi/
演示:https://www.youtube.com/watch?v=xcX-95iGKxY
感谢分享。
你好,
我怀疑 LabelSpreading() 类在这里的工作方式可能与您认为的不同。标签传播技术本质上是归纳的,这意味着它们只能对它们训练的无标签数据(即您最初情况下的 concatenate((X_train_lab, X_test_unlab)) 中的 X_test_unlab)进行预测。归纳方法不像普通的(演绎)分类器那样工作,也不能为看不见的数据(即 X_test)进行预测。因此,我认为 LabelSpreading() 在这里仍然可以无错误地运行,这很奇怪。在我看来,为了对 X_test 进行预测,X_test 需要通过 X_train_mixed = concatenate((X_train_lab, X_test_unlab, X_test)) 被包含在 model.train() 中。
.
我曾想,您的情况之所以能够无错误地执行,仅仅是因为您的 X_test 与用于训练算法的数据矩阵大小相同,concatenate((X_train_lab, X_test_unlab)) – 两者的大小都是 (500, 2)。但我使用不同大小的训练和测试矩阵运行了您的代码,它仍然不知何故可以运行。对我来说,鉴于我对标签传播方法如何工作的了解,这是一个奇怪的现象。您有什么想法?
也许可以调整数据集大小看看是否会产生影响?
嗨,Jason,
“半监督学习问题的关键是一致性的先验假设,这意味着:(1) 附近的点很可能具有相同的标签;以及 (2) 处于同一结构(通常称为簇或流形)的点很可能具有相同的标签。”
我的标记数据集的类别平衡/比例与我预期的未标记数据集不同。我认为这并没有违反上述假设,因为附近的点很可能共享相同的标签。只是两个数据集中的类别分布不同——我认为这没关系,但我很想听听您的看法。
非常感谢,
Ben
如果类别不平衡成为一个问题,它可能会促使您尝试过采样方法或成本敏感方法。
嗨!
LabelSpreading() 中使用的 kNN 的距离度量是什么?可以更改距离度量吗?
谢谢 🙂
Vi
不确定,可能是 sklearn 中 kNN 的默认设置。我建议您查阅文档。
您好!如何使用您自己的数据集来实现这一点?例如,CSV 文件中的表格数据。是否有其他帖子包含此内容?
您好 Gavin……以下内容可能对您有帮助
https://arxiv.org/abs/2108.12296