结合多个二元分类器 (LinearSVC) 进行多标签分类

Posted

技术标签:

【中文标题】结合多个二元分类器 (LinearSVC) 进行多标签分类【英文标题】:Combining Multiple Binary Classifiers (LinearSVC) for Multilabel Classification 【发布时间】:2021-12-24 08:45:39 【问题描述】:

我有一个包含 6 个类的数据集,它们可以映射到 4 个 one-hot-encoded 列,以便每个类对应于 one-hot-encodings 的不同组合:

Class one-hot1 one-hot2 one-hot3 one-hot4
0 class1 1 0 1 0
1 class2 1 0 0 0
2 class3 1 1 0 0
3 class4 0 0 1 0
4 class5 0 1 0 0
5 class6 1 1 0 1

我能够在每个 one-hot-encoded 列上拟合 4 个不同的二元分类器,它们都表现得相当好(大约 90% 的准确度,几乎没有偏差)。如何将这 4 个分类器组合成一个分类器,而不用每个分类器拟合不相关的数据?

二元分类器之一的示例:
# Optimized ngrams + features
transformer_one_hot_1 = FeatureUnion([
                ('feature1_tfidf', 
                  Pipeline([('extract_field',
                              FunctionTransformer(return_feature1, validate=False)),
                            ('tfidf', 
                              TfidfVectorizer(ngram_range=(2, 6), analyzer='char_wb', sublinear_tf=True, lowercase=False))])),
                ('feature2_tfidf', 
                  Pipeline([('extract_field', 
                              FunctionTransformer(return_feature2, validate=False)),
                            ('tfidf', 
                              TfidfVectorizer(ngram_range=(1, 7), analyzer='char_wb', sublinear_tf=True, lowercase=False))])),
                ('feature3_tfidf', 
                  Pipeline([('extract_field', 
                              FunctionTransformer(return_feature3, validate=False)),
                            ('tfidf', 
                              TfidfVectorizer(ngram_range=(1, 6), analyzer='char_wb', sublinear_tf=True, lowercase=False))])),
                ('feature4_tfidf', 
                  Pipeline([('extract_field', 
                              FunctionTransformer(return_feature4, validate=False)),
                            ('tfidf', 
                              TfidfVectorizer(ngram_range=(1, 8), analyzer='char_wb', sublinear_tf=True, lowercase=False))]))]) 


# Pipeline
pipeline_one_hot_1 = Pipeline(
        [
        ("tfidfs", transformer_one_hot_1),
        ("classifier", LinearSVC(class_weight='balanced')),
        ]
        )

# Fit the pipeline to the one-hot-encoded column of interest
pipeline_one_hot_1.fit(X_train, y_train['one-hot1'])

每个分类器(pipeline_one_hot_1pipeline_one_hot_2pipeline_one_hot_3 等)单独执行都相当不错。

现在我结合单独训练的二进制分类器的输出来生成预测的 one-hot-encoded 列:

one-hot-col-1 = pipeline_one_hot_1.predict(X_test)
one-hot-col-2 = pipeline_one_hot_2.predict(X_test)
one-hot-col-3 = pipeline_one_hot_3.predict(X_test)
one-hot-col-4 = pipeline_one_hot_4.predict(X_test)

然后我检查这些输出以查看它们是否对应于每个类的 one-hot-encodings。 但是,我最终想要的是一个接受数据帧/字典并返回单热编码向量的分类器:

prediction = combined_classifiers.predict(X_test)

其中prediction 是一个形状为(nsamples, n-onehotencodedcolumns) 的数组。

具体来说,我如何确保每个分类器都只针对相关数据进行训练? IE。我不想在one-hot2 列上训练pipeline_one_hot_1。有没有办法确保 StackingClassifier() 中的分类器在拟合时只看到某些数据,以便微调的模型不会拟合到错误的 one-hot-encoded 列?

【问题讨论】:

很少有人费心阅读和理解这么多信息。我强烈建议您只保留您的问题所需的信息 是的,这也是我的感觉。我会修改它以使其更简洁。 【参考方案1】:

严格回答您的问题:您可以简单地连接预测的布尔值并解码完整的 one-hot 向量。然后,您可以根据真实类别评估预测类别。

但是,这不太可能很好地工作,除非您有一些专业知识证明应该以这种方式划分类(例如,如果类之间存在某种层次顺序)。

一般来说,类标签不必是一次性编码,而不是分类特征。标签的分类性质可以安全地表示为数值,通常使用LabelEncoder。简而言之:这是因为模型没有也不能使用标签的数字顺序,而在以数字表示的分类特征的情况下,它会错误地依赖顺序。

【讨论】:

我确实有专业知识,所以这是可行的。我主要想做的是组合在单热编码列上训练的分类器,然后将它们的组合输出用作另一个预测类标签的分类器的输入。 如果您查看我的问题的第一个版本(在编辑中),则会有更多关于我的问题细节的详细信息。基本上堆叠是次优的,因为每个二元分类器的 LinearSVC 将被训练为每个类标签的一对一,这会降低性能,因为每个类都依赖于不同的特征和/或超参数。 好的,我明白了,您从真正的 OHT(6 个变量)开始,但现在它不再是 OHT,它是特定于数据集的表示。因此,假设您有充分的理由以这种方式训练独立分类器,它实际上或多或少是多标签分类。但是我看不出在预测的布尔变量上训练元分类器会有什么帮助:如果布尔值被正确预测,那么只有一个可能的类。如果出现错误(布尔值的不可能组合),它可能会默认为最可能的类。两者都可以确定地完成。 最后我编写了自己的自定义分类器。我将每个单独模型的置信区间堆叠成一个向量,并在该向量上使用另一个分类器来预测类整数 (1-6)。我的模型的准确率为 87%,而 StackingClassifier() 的准确率为 89%,尽管在导出时,我的自定义分类器的大小是原来的 1/10。 2% 的差异不足以证明夸大的模型大小是合理的,而且我的自定义分类器更易于解释。

以上是关于结合多个二元分类器 (LinearSVC) 进行多标签分类的主要内容,如果未能解决你的问题,请参考以下文章

从 Spark ML LinearSVC 解释 rawPrediction

SK了解如何获取 LinearSVC 分类器的决策概率

NLTK:调整 LinearSVC 分类器的准确性? - 寻找更好的方法/建议

关于多对多分类器的文献

sklearn多分类模型评测(LR, linearSVC, lightgbm)

如何将 TfidfVectorizer 的输出馈送到 Sklearn 中的 LinearSVC 分类器?