13

在过去的 2-3 周里,我一直在为这个问题绞尽脑汁。我有一个多标签(不是多类)问题,其中每个样本都可以属于多个标签。

我有大约 450 万个文本文档作为训练数据,大约 100 万个作为测试数据。标签约为 35K。

我正在使用scikit-learn。对于特征提取,我之前使用的是 TfidfVectorizer,它根本无法扩展,现在我使用的是 HashVectorizer,它更好,但考虑到我拥有的文档数量,它的可扩展性并不高。

vect = HashingVectorizer(strip_accents='ascii', analyzer='word', stop_words='english', n_features=(2 ** 10))

SKlearn 提供了一个 OneVsRestClassifier,我可以将任何估算器输入其中。对于多标签,我发现 LinearSVC 和 SGDClassifier 只能正常工作。根据我的基准,SGD 在内存和时间上都优于 LinearSVC。所以,我有这样的东西

clf = OneVsRestClassifier(SGDClassifier(loss='log', penalty='l2', n_jobs=-1), n_jobs=-1)

但这存在一些严重的问题:

  1. OneVsRest 没有 partial_fit 方法,这使得核外学习成为不可能。有没有其他选择?
  2. HashingVectorizer/Tfidf 都在单核上工作并且没有任何 n_jobs 参数。散列文档花费了太多时间。任何替代方案/建议?n_features 的值也正确吗?
  3. 我测试了 100 万份文档。散列需要 15 分钟,当涉及到 clf.fit(X, y) 时,我收到 MemoryError,因为 OvR 内部使用 LabelBinarizer 并且它试图分配一个几乎不可能分配的维度矩阵(yx 类)。我应该怎么办?
  4. 还有其他任何具有可靠且可扩展的多标签算法的库吗?我知道 genism 和 mahout,但他们都没有任何多标签情况?
4

4 回答 4

8
  1. 实现的算法非常简单:当有KOneVsRestClassifier个类时,它只适合K个二元分类器。您可以在自己的代码中执行此操作,而不是依赖. 您也可以在最多K个内核上并行执行此操作:只需运行K 个进程。如果您的机器中的类多于处理器,则可以使用诸如 GNU 并行之类的工具来安排培训。OneVsRestClassifier
  2. scikit-learn 中的多核支持正在进行中;Python 中的细粒度并行编程非常棘手。有潜在的优化HashingVectorizer,但我(哈希代码的作者之一)还没有考虑到它。
  3. 如果你按照我(和安德烈亚斯)的建议做你自己的一对一休息,这应该不再是问题了。
  4. (1.) 中的技巧适用于任何分类算法。

至于特征的数量,这取决于问题,但对于大规模文本分类 2^10 = 1024 似乎非常少。我会尝试 2^18 - 2^22 左右的时间。如果你训练一个带有 L1 惩罚的模型,你可以调用sparsify训练后的模型将其权重矩阵转换为更节省空间的格式。

于 2013-09-08T15:04:45.230 回答
8

我会手工完成多标签部分。OneVsRestClassifier 无论如何都将它们视为独立的问题。您可以只创建 n_labels 许多分类器,然后在它们上调用 partial_fit。但是,如果您只想散列一次(我建议),则不能使用管道。不确定加快散列矢量化器的速度。你得问@Larsmans 和@ogrisel ;)

拥有partial_fitOneVsRestClassifier 将是一个很好的补充,实际上我看不出它有什么特别的问题。您也可以尝试自己实现并发送 PR。

于 2013-09-08T15:02:10.377 回答
1

我对可扩展性的论点是,您应该使用更高级的问题转换方法集合,而不是使用 OneVsRest,这只是最简单的基线。在我的论文中,我提供了一种将标签空间划分为子空间并使用 Label Powerset 将子问题转换为多类单标签分类的方案。要尝试此操作,只需使用以下代码,该代码利用构建在 scikit-learn - scikit-multilearn之上的多标签库:

from skmultilearn.ensemble import LabelSpacePartitioningClassifier
from skmultilearn.cluster import IGraphLabelCooccurenceClusterer
from skmultilearn.problem_transform import LabelPowerset

from sklearn.linear_model import SGDClassifier

# base multi-class classifier SGD
base_classifier = SGDClassifier(loss='log', penalty='l2', n_jobs=-1)

# problem transformation from multi-label to single-label multi-class
transformation_classifier = LabelPowerset(base_classifier)

# clusterer dividing the label space using fast greedy modularity maximizing scheme
clusterer = IGraphLabelCooccurenceClusterer('fastgreedy', weighted=True, include_self_edges=True) 

# ensemble
clf = LabelSpacePartitioningClassifier(transformation_classifier, clusterer)

clf.fit(x_train, y_train)
prediction = clf.predict(x_test)
于 2017-02-16T23:29:01.683 回答
0

partial_fit()方法最近被添加到sklearn所以希望它应该在即将发布的版本中可用(它已经在主分支中)。

你的问题的规模使得用神经网络解决它很有吸引力。看看magpie,它应该比线性分类器给出更好的结果。

于 2016-08-31T12:07:17.760 回答