可扩展或在线的核心外多标签分类器

时间:2013-09-08 14:43:17

标签: machine-learning classification scikit-learn document-classification text-classification

在这个问题上,过去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万份文件。 Hashing需要15分钟,当涉及到clf.fit(X,y)时,我收到一个MemoryError,因为OvR内部使用LabelBinarizer并且它试图分配一个维度矩阵(y x类),这是不可能分配的。我该怎么办?
  4. 那里有任何其他可靠的图书馆。可扩展的多标签算法?我知道genism& mahout但他们两个都没有任何多标签情况?

4 个答案:

答案 0 :(得分:8)

  1. OneVsRestClassifier实现的算法非常简单:当有 K 类时,它只适合 K 二进制分类器。您可以在自己的代码中执行此操作,而不是依赖OneVsRestClassifier。您也可以在大多数 K 核心上并行执行此操作:只需运行 K 进程。如果您的计算机中有多个类而不是处理器,则可以使用GNU parallel等工具安排培训。
  2. scikit-learn中的多核支持正在进行中; Python中的细粒度并行编程非常棘手。 HashingVectorizer有潜在的优化,但我(其中一个散列代码的作者)还没有完成它。
  3. 如果你按照我(和安德烈亚斯)的建议做自己的一对一休息,这不应该是一个问题了。
  4. (1。)中的技巧适用于任何分类算法。
  5. 至于功能的数量,它取决于问题,但对于大规模文本分类2 ^ 10 = 1024似乎非常小。我会尝试2 ^ 18 - 2 ^ 22左右的东西。如果训练具有L1惩罚的模型,则可以在训练模型上调用sparsify以将其权重矩阵转换为更节省空间的格式。

答案 1 :(得分:7)

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

在OneVsRestClassifier上使用partial_fit将是一个很好的补充,实际上我没有看到它的特殊问题。您也可以尝试自己实现并发送PR。

答案 2 :(得分:1)

我对可伸缩性的论证是,您应该使用更高级的问题转换方法集合,而不是使用OneVsRest,它只是最简单的最简单的基线。在我的paper中,我提供了一种方案,用于将标签空间划分为子空间,并使用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)

答案 3 :(得分:0)

The partial_fit() method was recently added to sklearn so hopefully it should be available in the upcoming release (it's in the master branch already).

The size of your problem makes it attractive to tackling it with neural networks. Have a look at magpie, it should give much better results than linear classifiers.