假设我们要预测我们的朋友贾斯汀会喜欢哪些小说。我们有一张她最近读过的几本小说的清单,以及她是否喜欢每一本。对于这样的问题,标准的有监督的机器学习范式将包括比较正面例子(她喜欢的小说)和负面例子(她不喜欢的小说)的特征,以设计一个系统来预测未来尚未见过的小说会受到正面还是负面的欢迎。
另一方面,半监督范式不仅包括使用贾斯汀读过的小说,也包括她没有读过的小说,以准备对她的偏好做出预测。没有标签的例子(即我们不知道贾斯汀感觉的小说)比有标签的例子(即正面和负面的)要多得多。令人惊讶的是,在这样的情况下,未标记的数据实际上可以得到有效的利用。
为了开始理解未标记的数据如何帮助我们开发预测标签的模型,请考虑下面的漫画。假设我们有几个正数据点(下面用绿色表示)和几个负数据点(用红色表示)。为简单起见,我们假设每个数据点由两个功能描述。当我们形成一个模型来预测其他数据点是否为正或负时,这就像将特征平面划分为两个区域,其中一个区域的点被预测为正,而另一个区域的点被预测为负。根据我们是否知道未标记的数据点(以灰色表示)位于何处,我们对如何执行此操作的决定可能会有很大不同。
正-无标记学习是半监督学习的一个重要子范式,其中唯一可用的已标记数据点是正的。例如,假设我们只知道贾斯汀最喜欢的小说。(不管怎么说,她为什么要谈论那些她不喜欢的呢?)。
在这种情况下,标准的有监督机器学习范例将会运气不佳,因为任何标准模型的算法都需要训练正例和反例。但是,再说一次,尽管没有标签的数据点很模糊,但如果我们聪明地使用它们,在这里可能会有帮助。
考虑一下下面这幅新漫画。我们有一些积极的数据点(下面的绿色图示),但没有负面的。我们必须将特征平面划分为两个区域,其中一个区域中的点被预测为正,而另一个区域中的点被预测为负。如果我们知道未标记的数据点在哪里,那么我们关于如何做到这一点的决定将会非常不同!
人们对开发解决PU学习问题的方法非常感兴趣。由于标准机器学习问题(其中大量的正负数据点可以用来训练模型)是一个探索得很好的领域,有很多解决方法,所以大多数PU学习方法都涉及到对标准方法的巧妙适应。
以下是几种技术的快速总结,其中大部分将在稍后进行实验应用。
或许解决PU问题最明显的方法如下:将正数据点和未标记数据点分别视为正数据点和负数据点。对数据训练标准分类器模型。分类器将为每个数据点分配一个分数,积极的分数通常高于消极的分数。在未标记的数据点(临时标记为负数)中,分数最高的数据点最有可能是正数。
Elkan和Noto在“仅从积极的和未标记的数据中学习分类器”(2008年)中探索了这种最幼稚的方法,并在一定程度上证明了这一点是合理的。这篇论文的中心结果是,在某些基本但对于现实目的可能略有不合理的假设下,对正数据和未标记数据训练的标准分类器应该给出的分数应该与它在对正数据和负数据进行适当训练时给出的分数成正比。
正如作者所指出的,“这意味着,如果(假设正确训练的)分类器仅用于根据样本属于[阳性]的概率对它们进行排序,那么可以直接使用[对阳性和未标记数据进行训练]的分类器。”
对于给定的PU问题,一种相关但更复杂的方法涉及装袋的变体:
通过将所有正数据点与来自未标记点的随机样本进行替换来创建训练集。
从这个“Bootstrap”样本构建分类器,将正数据点和未标记数据点分别视为正数据点和负数据点。
将分类器应用于随机样本中未包括的任何未标记数据点(以下称为OOB(“袋子外”)点),并记录它们的分数。
重复上述三个步骤多次,最后将收到的OOB分数的平均值分配给每个点。
描述这种方法的一篇论文是Mordelet和Vert的A BagingSVM to Learning from Positive and Unlabed Example(2013)。根据作者的说法,“该方法可以与最先进的PU学习方法相媲美,甚至优于最先进的方法,特别是当正例的数量有限,而未标记的示例中的反例的比例很小时,尤其是在这种情况下,该方法的性能可以与最先进的PU学习方法相媲美,甚至优于最先进的方法。建议的方法也可以比最先进的方法运行得快得多,特别是当未标记的示例集合很大时。“。
各种各样的PU学习策略都属于“两步法”的一般范畴。在Kaboutari、Bagherzadeh和Kheradmand所著的“文本分类中正面无标签学习的两步技术评估”(2014)中,对这些技术进行了不错的介绍。
识别可以确信地标记为阴性的未标记数据点的子集。(上述论文的作者称这些观点为“可靠的负面因素”。)。
使用正数据点和负数据点训练标准分类器,并将其应用于其余未标记的点。
通常,第二步的结果用于返回第一步并迭代。如上所述,“如果[可靠否定]集合包含大多数否定文档并且足够大,则学习算法…。工作非常好,将能够建立一个良好的分类器。但通常是在步骤1…中标识的一组非常小的负面文档。然后,学习算法反复运行,直到收敛或满足某种停止标准。“。
Shubham Jain在最近的一篇博客文章“伪标签简介:一种半监督学习技术”中提出了类似的方法,但其中的细节并不是专门针对PU问题的。
这里值得一提的是最后一个开发,尽管它不会包括在我们下面的实验中,它是Li和华在“走向并行数据挖掘的正向无标签学习:随机森林框架”(2014)中介绍的一种算法。
通过对合成数据集…和真实数据集UCi的实验,提出的框架称为PURF(正无标记随机森林),能够从正的和未标记的实例中学习,并且通过并行计算获得与由全标记数据训练的RF相当的分类性能,并且在合成的和真实的UCi数据集上都能获得与完全标记的数据训练的RF相当的分类性能。该框架将包括广泛使用的PU信息增益(PURF-IG)和新开发的PU基尼指数(PURF-GI)在内的PU学习技术与可扩展的并行计算算法(即RF)相结合。“
此外,作者报告说他们已经“基于SCRICKIT-LEARN包用Python实现了PURF”,所以如果代码在某个时候可以公开使用,它可能是一个很有前途的工具。
在下面的所有代码中,假设我们有一个熊猫数据帧X的特性和一个熊猫系列y的目标(1表示正面,0表示其余的)。
#为latery_orig=y.copy()保持原始目标的安全#取消一定数量的数据点的标签shidden_size=#在此处输入数字#y.loc[np随机选择(y[y==1].index,Replace=false,size=HIDDEN_SIZE)]=0。
得到的数据集是我们将用来根据前面概述的方法构建模型的数据集。之后,我们可以通过确定他们在多大程度上成功地识别出我们对他们隐藏的积极因素来判断他们的有效性。
从sklearn.ensemble导入RandomForestSorfierrf=RandomForest分类器(FORN_ESTIMATERS=1000,FOR#1000棵树:FRON_JOBS=-1树,#使用所有CPU核心)rf.fit(X,y)。
Results=pd.DataFrame({PROUT&39;TRUE&39;TRUSE:Y_ORIG,):Y_orig,:#True Labels;';Label:Y,:Y,#显示给模型的#个标签:Output_Std&39;:rf.Forect_Proba(X)[:,1]和#Random Forest的分数。,';标签';,';OUTPUT_STD';])。
为方便起见,我们将其他方法的输出存储在相同的数据帧中。
跟踪正数据点和未标记数据点的指数非常方便:
对于每个数据点,我们还将记录它被OOB的次数,以及它收到的OOB分数的总和:
Num_OOB=pd.DataFrame(np.zeros(Shape=Y.Shape),index=y.index)sum_OOB=pd.DataFrame(np.zeros(Shape=Y.Shape),index=y.index)。
For_in range(N_Stiators):*#获取本轮未标签点的引导样本#ib=np随机选择(Iu,Replace=True,size=len(Ip))#查找本轮的OOB数据点i_oob=list(set(IU)-set(Ib))#获取训练数据(所有正值和未标签点的引导#样本)并构建树:xB=X[y&。0].append(y.loc[ib])*stistiator.fit(xB,yb)*#记录本轮的OOB分数::sum_oob.loc[I_OOB,0]+=stistiator.Forect_Proba(X.loc[I_OOB])[:,1]Num_oob.loc[I_OOB,0]+=1。
PU打包方法是如此优雅(正如我们将看到的那样,功能也非常强大),因此我决定创建一个利用并行化的更用户友好的实现。我的实现相当简单地改编自SCRKIT-LEARN中的BaggingTyfier。代码可以在这里提供的bagingPU.py文件中找到。使用我的实现,上面的所有代码都可以替换为以下代码:
From bagingPU import BaggingSorfierPUbc=BaggingClassfierPU(数据决策树分类器(),n_估计器=1000,n_job=-1,max_Samples=sum(Y)#每个训练样本将被平衡)bc.fit(X,y)Results[';output_Bag';]=bc.ob_Decision_Function_[:,1],bc.fit(X,y)Results[';output_Bag';]=bc.ob_Decision_Function_[:,1]。
在一台有4个内核的机器上,这个新的代码片段运行时间大约是以前的四分之一。
在两步方法中,数据点将带有三个指定之一(正、未标记或负),并且许多点将在此过程中重新指定。因此,我们首先创建一个新的目标向量,1表示正向量,-1表示未标记向量,0表示“可靠的负值”。
当然,一开始就没有可靠的负面因素。对于步骤1,我们将使用前面的分数:
让我们找出给予已知正数据点的分数范围:
步骤1:如果任何未标记的点得分低于所有已知的正值,则将其标记为负值。另一方面,如果它的得分高于所有已知的积极因素,我们不妨给它贴上积极的标签。
Ip_new=ys[(ys<;0)&;(pred&>;=range_P[1])].indexiN_new=ys[(ys<;0)&;(pred<;=range_P[0])].indexys.loc[IP_new]=1ys.loc[in_new]=0。
我们将把自己限制在最多10次迭代。这是一个武断的选择,但如果我们只是等待它停止寻找和标记新的负片,这种方法可能需要很长时间。(此外,正如前面提到的和我们将在实验中看到的那样,将我们自己限制在单个迭代中甚至可能已经足够好了。)。
对于I in Range(10):如果步骤1没有找到新标签,如果步骤1没有找到新标签,则如果len(Ip_New)+len(In_New)==0且i>;0:0:0,则重新打印(步骤1标记为%d个新正片和%d个新负片。';步骤1标记为%d个新正片和%d个新负片。';n#39;n#3%(len(Ip_New),len(In_New)。';,end=';';)#重新训练新标签并获得新分数:rf2.fit(X,ys);repred=rf2.Forect_Proba(X)[:,-1]#查找给予正数据点的分数范围:Range_P=[min(pred*(ys>;0)),max(pred*(ys>;0))];#重复步骤1:IP_。(prd>;=range_P[1])].index=in_new=ys[(ys<;0)&;(pred<;=range_P[0])].index=ys.loc[IP_new]=1;ys.loc[in_new]=0。
作为与其他方法比较的第四种方法,我们可以计算三种主要方法分配给每个数据点的平均分数。
在此之后,我们准备比较不同方法的表现-即他们能多好地识别隐藏的积极因素。
我们将通过将上面开发的一些方法应用于几个人工数据集来测试它们。在接下来的帖子中,我将展示使用某一实际数据集时的结果。
这个实验的完整代码可以在这个GitHub链接上找到。一些不太有趣的代码,特别是用于生成图形的代码,没有包含在本文中。
从sklearn.dataSets导入Make_Circle X,y=Make_Circle(n_Samples=6000,Noise=0.1,Shuffle=True,factor=.65)X=pd.DataFrame(X,Columns=[';Feature 1';,';Feature 2';])y=pd.Series(Y)。
-所以三分之一的阳性将被取消标记。产生的数据集在这里可视化。我们可以看到,人工数据由两个点的同心圆区域组成,正值区域组成最里面的区域。
为了测试各种学习PU的方法,我们将运行前面列出的所有代码。下面的图表显示了通过使用标准分类器和使用PU打包方法分配给无标签点的分数。
在视觉层面上,这两种方法之间似乎没有什么不同,除了PU装袋比标准分类器分配的分数范围更广。
PU装袋的两种不同实现显然执行起来几乎相同。这在随后的所有实验中都是如此(如下所述),这表明这两个实现实际上是相同的-正如预期的那样!唯一真正的区别是,我的改编自SCRKIT的并行版本-学习速度要快得多。
下面的图表直观地展示了两步法。在左侧,我们可以看到哪些数据点在第一步中被标记为“可靠负片”。请注意,相当数量的预期负片立即被重新标记为“可靠负片”。右侧的图表显示了在两步过程的几次迭代之后分配给未标记点的分数。
从视觉上看,我的两步方法的输出似乎与标准分类器差别很小。
让我们更仔细地看看这三种主要方法的性能,根据它们识别隐藏在未标记的点中的积极因素的能力来判断每种方法的性能。以下是直观的摘要:
无论我们使用哪种方法,如果我们只选择500个“最好”的无标记点--也就是得分最高的点--结果发现,其中90%以上实际上是隐藏的积极因素,虽然这三种不同的方法表现大致相同,但PU装袋方法的表现明显落后于其他方法。这不应该太令人惊讶;正如前面所引用的,“当正面示例的数量有限时”,这种方法工作得特别好,但这里的情况并非如此。
这样90%的阳性都不会被贴上标签。新的数据集在这里可视化。
在运行所有与前面相同的代码之后,下面的图表可视化了由三种主要方法中的每一种方法分配的分数。由此看来,PU套袋似乎比其他方法做得更好。
正如承诺的那样,在这种情况下,PU套袋肯定比其他两种方法性能更好。让我们试着走到更极端的地方。
下一次实验的完整代码可以在这个GitHub链接上找到。要创建我们的“月球”数据集,请执行以下操作:
从sklearn.DataSets导入make_moonsX,y=make_moons(n_Samples=6000,Noise=0.1,Shuffle=True)X=pd.DataFrame(X,Columns=[';Feature 1';,';Feature 2';])y=pd.Series(Y)。
这是第二个数据集的可视化,去掉了1000个正值中的标签。
由标准分类器和PU装袋给予未标记数据点的分数如下所示。
在这种情况下,不同的方法在识别隐藏的积极因素的能力上似乎非常相似。
由于90%的阳性没有标记,下面是分数可视化和性能比较。
此实验的完整代码可通过此链接获得。要创建我们的“BLOBS”数据集,请执行以下操作:
From sklearn.datets.Samples_Generator导入make_bloobs X,y=make_bloobs(n_sample=6000,center=[[1,5],[5,1],[0,0],[6,6]])X=pd。DataFrame(X,Columns=[';Feature 1';,';Feature 2';])#将原始标签从[0,1,2,3]转换为仅[0,1]y=(y>;1)。Astype(Int)y=pd。系列(Y)。
下面是最后一个人造数据集,去掉了1000个阳性的标签。
下面直观地显示了三种主要方法给出的分数,然后是性能比较。
和以前一样,由于只隐藏了三分之一的积极因素,PU装袋方法有点落后于其他方法。
由于90%的阳性没有标记,下面是分数可视化和性能比较。
对于我们最终实验的这个最极端的版本,99%的积极因素都被隐藏了,让我们尝试一些新的东西。我们将运行通常的三种主要方法,但是除了通常的决策树实现之外,我们还将尝试使用支持向量机(也称为SVM,或者在我们正在使用的skLearning实现中特别是SVC)作为底层分类器进行PU打包。
以下是三种常用方法和新方法分配的分数的可视化。
使用支持向量机而不是树木(顺便说一句,就像论文中PU装袋方法所基于的那样)似乎在很大程度上是最好的。为了确定,让我们仔细看看。以下是常用的三种方法的比较性能:
PU装袋(使用决策树)与其他方法有很大的不同。现在让我们比较一下基于树和基于支持向量机的PU装袋。
在这个使用玩具数据集的实验中,由于绝大多数阳性结果隐藏在未标记的点中,支持向量机分类器的PU袋化是明显的赢家。