在没有所有可能标签的情况下训练sklearn LogisticRegression分类器

5 投票
3 回答
2646 浏览
提问于 2025-04-17 16:49

我正在尝试使用 scikit-learn 0.12.1 来做以下几件事:

  1. 训练一个逻辑回归分类器
  2. 在保留的验证数据上评估这个分类器
  3. 给这个分类器输入新数据,并为每个观察结果获取最可能的5个标签

使用 Sklearn 进行这些操作非常简单,但有一个特别的问题。就是没有保证每一个可能的标签都会出现在用来训练分类器的数据中。可能的标签有好几百个,而其中一些在可用的训练数据中并没有出现。

这导致了两个问题:

  1. 标签向量化器在验证数据中遇到之前未见过的标签时无法识别。这可以通过将标签器适配到所有可能的标签集合来轻松解决,但这又加重了第二个问题。
  2. 逻辑回归分类器的 predict_proba 方法输出的是一个 [n_samples, n_classes] 的数组,其中 n_classes 只包含在训练数据中见过的类别。这意味着对 predict_proba 数组进行排序时,得到的值不再直接对应于标签向量化器的词汇表。

我的问题是,如何才能让分类器识别所有可能的类别,即使其中一些在训练数据中没有出现?显然,它会很难学习那些从未见过的数据的标签,但在我的情况下,0 是完全可以用的。

3 个回答

2

在larsman的精彩回答基础上,我得到了这个:

from itertools import repeat
import numpy as np

# determine the classes that were not present in the training set;
# the ones that were are listed in clf.classes_.
classes_not_trained = set(clf.classes_).symmetric_difference(all_classes)

# the order of classes in predict_proba's output matches that in clf.classes_.
prob = clf.predict_proba(test_samples)
new_prob = []
for row in prob:
    prob_per_class = zip(clf.classes_, prob) + zip(classes_not_trained, repeat(0.))
    # put the probabilities in class order
    prob_per_class = sorted(prob_per_class)
    new_prob.append(i[1] for i in prob_per_class)
new_prob = np.asarray(new_prob)

new_prob是一个[n_samples, n_classes]的数组,和predict_proba的输出格式一样,不过现在它包含了之前没有见过的类别的0概率。

3

如果你想要一个像 predict_proba 返回的那种数组,但想要列的顺序是按照 all_classes 排序的,那你可以试试这个方法:

all_classes = numpy.array(sorted(all_classes))
# Get the probabilities for learnt classes
prob = clf.predict_proba(test_samples)
# Create the result matrix, where all values are initially zero
new_prob = numpy.zeros((prob.shape[0], all_classes.size))
# Set the columns corresponding to clf.classes_
new_prob[:, all_classes.searchsorted(clf.classes_)] = prob
8

这里有个解决办法。首先,确保你有一个叫做 all_classes 的类列表。然后,如果 clf 是你的 LogisticRegression 分类器,

from itertools import repeat

# determine the classes that were not present in the training set;
# the ones that were are listed in clf.classes_.
classes_not_trained = set(clf.classes_).symmetric_difference(all_classes)

# the order of classes in predict_proba's output matches that in clf.classes_.
prob = clf.predict_proba(test_samples)
for row in prob:
    prob_per_class = (zip(clf.classes_, prob)
                    + zip(classes_not_trained, repeat(0.)))

这段代码会生成一个包含 (cls, prob) 组合的列表。

撰写回答