常规机器学习算法如何处理多标签问题
- 2021 年 3 月 23 日
- AI
什么是多标签分类:
让我们看一下下面的图片。

如果我问您该图像是否包含房屋怎么办?该选项将为YES或NO。
考虑另一种情况,我们要同时回答多个问题:

这就是一个典型的多标签分类问题,标签存在多个不同的类型。
首先要搞清楚多标签分类和多分类问题的区别,二者的形式很类似,容易混淆,看下图:

例如,上面的这部电影,这部电影被评为“ U / A”(意思是“针对12岁以下儿童需要父母陪同观看”),还有其他类型,例如“ A”(仅限成人)或“ U”(无限制),但是每部电影一定只能是这三种类型中的一种(简单来说每一行的样本的标签必然是只有一个1,其它都是0的形式),其标签转化为具体的机器学习算法的输出大概长这样:
[UA,0,0],
[0,A,0],
[0,0,U]
这是多分类问题,当然常见的lgb或者tf这类的都能够支持 1,3,2,1。。。这样的不需要onehot的原始的多分类标签的形式,也能够支持onehot转化之后的形式,这个问题不大,就是一个简单的转换而已。
但是考虑电影的类型,一部电影可以是“comedy”和“romance”两种类型,喜剧是电影在悲剧、喜剧、中性剧下的标签,浪漫则是在“惊悚”,“科幻”,“记录”。。。等判定标准下的另外一种标签。这意味着每部电影存在多个不同类型的标签,而多分类则是存在同一个类型的多标签。
简单来说,二分类和多分类都属于多标签分类的特例,当标签的“类型”仅仅为一的时候,多标签分类问题退化为多分类问题,当单一类型的标签的取值仅为0或者1的时候,多分类问题退化为二分类问题。
我们可以看一下下面的一个例子:

这里的y就是一个典型的多标签的情况,如果是多分类,则y的每一行必定仅存在一个1,如果是多标签,则每一行可以有0个或者多个1。
和时间序列的多步预测一样,lr和gbdt这类常见的机器学习算法和接口难以直接处理这样的输出形式,因此我们需要使用不同的策略来间接使用机器学习算法
下面举一个简单的例子:(这里的例子是多输出问题,多输出问题包括了多标签分类和多标签回归,除此之外,子任务如果既存在离散的分类型输出和连续的回归型输出则我们统称为多输出问题,多目标学习可以应用到多输出问题中,但是注意,多目标学习和多输出问题是一个交集的关系,当多目标学习中的多个目标对应不同的数据集时,此时问题不再是多输出问题,仅仅在多目标学习中的多个目标对应的是同一个数据集的时候,才是多输出问题)
X y1:性别 y2:年龄 y3:收入
用户1的各种特征 男 25岁 30万
用户2的各种特征 女 35岁 40万
任务是根据特征X,预测这个用户的性别、年龄和收入
策略1、转化为多个子问题
问题1:二分类问题,预测性别为男或女
X y1:性别
用户1的各种特征 男
用户2的各种特征 女
问题2:回归问题,预测用户的年龄
X y2:年龄
用户1的各种特征 25岁
用户2的各种特征 35岁
问题3:回归问题,预测用户的收入
X y3:收入
用户1的各种特征 30万
用户2的各种特征 40万
训练的时候针对每一个子问题分别建立一个模型,预测的时候三个模型分别输出预测结果,本质上就是多标签问题转化为多个单标签的子问题。
这种问题的处理方法很简单,我们可以把标签y进行循环,每次取一列出来作为单标签子问题的标签,后续的步骤就和常规的分类或回归问题的处理方式一样了,不需要再写更多代码。
这种方法虽然简单,但是最大的缺点就是没有考虑标签之间的相关性,例如用户是男性,职业为程序员,年龄为30岁,工作地点是上海,则其收入大概率会为30万。从而导致分类的精度降低;
策略2、转化为多个相关的子问题
这种策略更进一步,本质上和机器学习算法处理时间序列多步预测的迭代策略一致。

例如上图是一个4标签分类问题,我们可以这么转换:

这种方法的精度往往会更高并且不会有什么标签泄露的问题因为不同类型的标签本来就没什么关系;
和时间序列预测中的迭代法一样,这种方式的处理也存在缺陷:
1、误差累计的问题,如果模型1的精度很差,则后续的预测会引入误差,从而使得后面的模型的精度越来越差;
2、多标签问题独有的缺陷,我们并不知道多个子任务之间的顺序关系(时序问题的顺序关系是自然就有的,t时刻的预测结果必然作为t+1时刻的输入特征),这涉及到对不同类型的标签的预测的先后顺序需要进行穷举,在多标签问题中如果标签的类型数量很多,则效率很低,但是如果选择了不好的预测顺序,则最终的模型的精度差异可能很大,除非不同类型的标签之间的相关性很低,但是如果相关性很低则其实使用策略1就够了。
这种实现也很简单,和策略一基本一样,只不过没法并行了,因为后续的模型需要在前一个模型的预测结果作为特征入模之后才可以训练。
策略3、将多标签转化为多分类问题
这种方法也非常的简单直观,例如:

我们发现x1和x4的多标签情况是一样的,x3和x5的多标签情况也是一样的,则我们可以把x1和x4的标签转化为单标签1,其它如法炮制,如下图:

这种方法也比较简单,但是也存在着巨大的缺陷,当我们的未来数据集中存在不同的组合情况的时候,

例如测试集有一个样本的多标签是[1,1,0,0],则模型无法正确预测,因为我们的训练标签里压根就没有这种多标签的情况。这和labelencoder在test数据集出现没有encode过的类别的问题是一样的,并且严格来说,这种方式是将一个n维(n是多标签的类型)的问题降维到1维的问题上,最终的效果好坏其实不好确定的,另外对于多输出(即存在离散的标签类型和连续的标签类型的问题),这种方法就没法使用了。
策略4、展平
策略4仅仅适用于多标签分类的问题,思路很简单,假设有一个样本的多标签为:
X 【1,A】
则我们进行展平后为:
X [1]
X [A]
需要注意的是,1和A必须是同一个语义空间下的标签,例如医疗里的一些问题:
患者A [糖尿病,肾结石,癌症]
患者B [胃溃疡,肠道炎]
这是一种比较特殊的多标签问题,即多个标签实际上属于同一种类型,也是比较常见的问题,例如电影的类型为“浪漫”,“惊悚”,浪漫和惊悚是同一个语义空间下的定义,即二者是同一种类型。
这种情况下,我们可以进行展平,转化为常规的多分类问题。
策略5、换nn
神经网络灵活的构造使其可以适用于上述所有类型的问题,例如对于最棘手的多输出问题,标签中既有离散又有连续类型的标签,则我们可以在输出层分别接一个softmax和一个linear的任务层,然后设置好样本和标签的形式,使用tf.keras或者torch的框架可以很简单的写出来;
同时多标签分类的另一个需要注意的比较麻烦的问题:
当标签空间很大时,多标签分类往往会出现分类器过拟合和欠拟合的问题,尤其是在问题转换方法中。解决此问题的一种众所周知的方法是将问题分解为带有较小标签子集的子问题,以提高泛化质量。
当标签空间很大的时候,某些标签类型下的样本可能非常的稀少,此时策略1,2,3在这种类型的标签下学习出来的模型效果会很差(nn的结构虽然可以自然地适配多输出问题,但是某一个输出层对应的标签的数量非常的不平衡,比如某一个分类输出层几乎全是0,很少有1,则模型的整体性能也会受到影响,多目标学习的任务之一也是致力于解决这种问题,通过多个目标同时优化来提高在某个任务上的泛化性能),这个时候,我们要做的事情就是进行简单的标签聚类,从而将很多标签问题转化为不多标签问题。
策略6、基于图
这种策略和策略4比较类似,但是比策略4更进一步,策略4仅仅是对多标签进行简单的label encoder(处理方法很简单,把多标签变成字符串,例如[0,1,2]变成”0,1,2″然后label encoder即可)基于图的方式也很简单,假设某个样本的标签为[男,程序员,上海](性别,职业,工作城市三种类型的标签),则我们将“男”,“前端”,“上海”当作3个独立的同质的节点,如果有10个样本都是这样的多标签情况,则“男”,“前端”,“上海”这三个标签的权重互为10(无向图),然后使用louvain,infomap,walktrap之类图聚类算法对多标签进行聚类,假设“男”,“前端”,“上海”和“女”,“前端”,“北京”以及“男”,“算法”,“上海”在同一个社区里,则我们统一打标为“一线码农”。
这种方式的主要的好处在于,从图的角度考虑了标签之间的关联性质,坏处在于:
1、太糙,标签聚类本身就丧失了很多细节的信息了,图聚类算法本身也基于不同的假设存在着一定的误差;
2、对于多输出问题,有离散和连续标签的问题,难以使用,例如收入这样的连续特征,可能每个人的收入都不一样。
策略7、专家法
人工打标,例如欺诈问题里,可能把薅羊毛划分为个体欺诈者,把狂薅羊毛、团伙盗刷、团伙身份盗用等划分为团体欺诈者。
这种方式依赖人类先验知识,没啥好说的。
策略6和策略7,本质上已经把问题转化为另一个问题了,因为你的预测结果其实比较难转化到原来的标签上,比如前面说的“一线码农”的定义,即使预测出这个类别,也很难直接转化为“女”,“前端”,“北京”这样的标签上,除非我们针对“一线码农”的数据再训练一个多标签分类的模型。
策略8、多标签的embedding
这种思路就更风骚了。。我真是服了,多标签还有这种多做法,烦死了。

比如“女”,“前端”,“北京”经过graph embedding之后会得到3个节点向量,进行简单相加得到这个用户的标签的embedding,然后我们构建一个回归器,用X来预测embedding的结果,得到预测数据集的embedding向量,然后用faiss之类的工具来找最近邻得到预测用户的多标签预测结果。
没了,后面估计要研究研究多目标学习了,参考自:
scikit-multilearn | Multi-label classification package for Python
Solving Multi-Label Classification problems (Case studies included)