计算由不相交分类器组成的分类器的ROC曲线的高效算法


13

假设我有不相交的分类器C_1 ... C_n,因为在同一个输入(例如决策树中的节点)上,没有两个返回真。我想建立一个新的分类器,将它们的某些子集结合起来(例如,我要决定在决策树的哪些叶子上给出肯定的分类)。当然,这样做会在敏感性和阳性预测值之间进行权衡。因此,我希望看到ROC曲线。原则上,我可以通过枚举分类器的所有子集并计算所得的灵敏度和PPV来做到这一点。但是,如果n大于30左右,这将是非常昂贵的。另一方面,几乎可以肯定,有些组合不是帕累托最优的,因此可能会有一些分支定界策略或类似的东西,

我想就这种方法是否可能取得成果,是否有任何工作或您是否有关于在上述情况下有效计算ROC曲线的想法提出建议。


您是否将每个输入案例分类为true或false?
image_doctor

@image_doctor:是的
乔什·布朗·克雷默

我不清楚,“ ...在不相交的意义上,没有两个将在同一输入上返回true ...”,并且您正在分类为二进制输出,如何在您的分类器中拥有两个以上的分类器合奏,我可能丢失了一些东西吗?
image_doctor

@image_doctor:您可能在想,我是说没有两个分类器在同一输入上返回相同的输出。我是说没有两个人会返回true。它们都可以返回false。
Josh Brown Kramer 2015年

1
也许本文以理论上最优的方式来组合ROC分类器(或引用该文献的论文)可以帮助您了解最新技术水平:M。Barreno,A。Cardenas,JD Tygar,最优ROC曲线用于分类器组合,神经信息处理系统的进展,2008
。– Valentas

Answers:


1

N10

这听起来很像背包问题!群集大小是“权重”,群集中正样本的数量是“值”,并且您想用尽可能多的值填充固定容量的背包。

valueweightkk0N

1k1p[0,1]k

这是一个python示例:

import numpy as np
from itertools import combinations, chain
import matplotlib.pyplot as plt
np.random.seed(1)
n_obs = 1000
n = 10

# generate clusters as indices of tree leaves
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_predict
X, target = make_classification(n_samples=n_obs)
raw_clusters = DecisionTreeClassifier(max_leaf_nodes=n).fit(X, target).apply(X)
recoding = {x:i for i, x in enumerate(np.unique(raw_clusters))}
clusters = np.array([recoding[x] for x in raw_clusters])

def powerset(xs):
    """ Get set of all subsets """
    return chain.from_iterable(combinations(xs,n) for n in range(len(xs)+1))

def subset_to_metrics(subset, clusters, target):
    """ Calculate TPR and FPR for a subset of clusters """
    prediction = np.zeros(n_obs)
    prediction[np.isin(clusters, subset)] = 1
    tpr = sum(target*prediction) / sum(target) if sum(target) > 0 else 1
    fpr = sum((1-target)*prediction) / sum(1-target) if sum(1-target) > 0 else 1
    return fpr, tpr

# evaluate all subsets
all_tpr = []
all_fpr = []
for subset in powerset(range(n)):
    tpr, fpr = subset_to_metrics(subset, clusters, target)
    all_tpr.append(tpr)
    all_fpr.append(fpr)

# evaluate only the upper bound, using knapsack greedy solution
ratios = [target[clusters==i].mean() for i in range(n)]
order = np.argsort(ratios)[::-1]
new_tpr = []
new_fpr = []
for i in range(n):
    subset = order[0:(i+1)]
    tpr, fpr = subset_to_metrics(subset, clusters, target)
    new_tpr.append(tpr)
    new_fpr.append(fpr)

plt.figure(figsize=(5,5))
plt.scatter(all_tpr, all_fpr, s=3)
plt.plot(new_tpr, new_fpr, c='red', lw=1)
plt.xlabel('TPR')
plt.ylabel('FPR')
plt.title('All and Pareto-optimal subsets')
plt.show();

这段代码将为您画一张漂亮的图画:

TPR,FPR和最佳曲线

210

现在有点麻烦了您根本不必理会子集!我所做的是按每个正样本中的分数对树叶进行排序。但是我得到的正是树概率预测的ROC曲线。这意味着,您不能通过根据训练集中的目标频率手动挑选其叶子来胜过它。

您可以放松并继续使用普通的概率预测:)


好点子。从理论上讲,“正调用”的数量仍然可能成倍增加,但实际上这可能不是问题。
Valentas

为什么通话次数成倍增长?我计算每个群集的值/权重(采用线性时间),对它们进行排序(N * log(N)),并针对每个前K个群集(也可以使其线性)评估TPR和FPR。
大卫·戴尔

您可以为肯定预测的每个可能值求解背包,并且子集数量呈指数级增长。但这是理论上的技术性问题,如果您专门要求凸包内部的点,这并不有趣-这应该是公认的答案。
Valentas

@Valentas,好的,我明白你的意思。但是,如果您对某些叶片进行随机预测,则可以到达凸包中的任何点。因此,在这种情况下,船体就是ROC本身。
David Dale

@DavidDale,总结一下:1)相对于(敏感性,PPV)都是最优的每种策略,在具有该肯定预测数量的策略中,最大化真实阳性的数量。2)这是背包问题。3)按正例数/例数顺序选择节点是解决背包问题的一个很好的近似解决方案。4)但这与选择概率阈值相同。
乔什·布朗·克雷默

0

我可能建议您使用贪婪的方法。给一个分类器开始,您将包括使整体获得最佳性能改进的分类器。如果无法改善,请添加更多分类器,然后停止。您将从每个分类器开始。复杂度最多为N * N。

我还有一个问题,“帕累托最优”是什么意思,尤其是在您所处的环境中?我从Wiki中找到了这种解释,https://en.wikipedia.org/wiki/Pareto_efficiency

通过重新分配,可以改善至少一个参与者的幸福感,而不会降低任何其他参与者的幸福感。

帕累托效率的提高是针对每个参与者的,这可能对应于每个分类器。您如何定义一个分类器的改进?


1
我的意思是:如果我有合奏1和2,且(灵敏度,正预测值)分别为(.90,.80)和(.97,.93),则1不是帕累托最优,因为存在另一个合奏,即2,以各种方式击败了它。关于您提出的算法:灵敏度和PPV之间需要权衡,因此“整体获得最佳性能改进”的定义不明确。
乔什·布朗·克雷默
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.