结合多个二元分类器 (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_1
、pipeline_one_hot_2
、pipeline_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
NLTK:调整 LinearSVC 分类器的准确性? - 寻找更好的方法/建议