在这个问题上,过去2-3周我一直在绞尽脑汁。
我有一个多标签(不是多类)问题,每个样本都可以属于几个标签。
我有大约450万个文本文档作为训练数据,大约100万个作为测试数据。标签大约35K。
我在用 scikit学习。对于特征提取,我之前使用的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)
但这有一些严重的问题:
- OneVsRest没有partial_fit方法,这使得无法进行核外学习。那有什么替代品吗?
- HashingVectorizer / Tfidf都可以在单个核心上运行,并且没有任何n_jobs参数。散列文档需要花费太多时间。任何替代/建议? n_features的值是否正确?
- 我测试了100万份文件。 Hashing需要15分钟,当涉及到clf.fit(X,y)时,我收到一个MemoryError,因为OvR在内部使用LabelBinarizer,它试图分配一个维度矩阵(y x类),这是不可能分配的。我该怎么办?
- 还有其他任何具有可靠和可扩展的多标签算法的库吗?我知道genism和mahout但他们两个都没有任何多标签情况?
我会手工做多标签部分。无论如何,OneVsRestClassifier将它们视为独立问题。您可以创建n_labels许多分类器,然后在它们上调用partial_fit。但是,如果您只想哈希一次(我建议),则不能使用管道。
不确定加速哈希矢量化器。你得问@Larsmans和@ogrisel;)
有 partial_fit
在OneVsRestClassifier上是一个很好的补充,实际上我没有看到它的特殊问题。您也可以尝试自己实现并发送PR。
- 那个算法
OneVsRestClassifier
工具很简单:它很合适 ķ 二元分类器有的时候 ķ 类。您可以在自己的代码中执行此操作,而不是依赖于此 OneVsRestClassifier
。你最多也可以这样做 ķ 并行核心:运行 ķ 流程。如果您的计算机中有多个类而不是处理器,则可以使用GNU parallel等工具安排培训。
- scikit-learn中的多核支持正在进行中; Python中的细粒度并行编程非常棘手。有潜在的优化
HashingVectorizer
但是我(其中一个哈希码的作者)还没有完成它。
- 如果你按照我(和安德烈亚斯)的建议做自己的一对一休息,这应该不再是问题了。
- (1.)中的技巧适用于任何分类算法。
至于功能的数量,它取决于问题,但对于大规模的文本分类2 ^ 10 = 1024似乎 非常 小。我会尝试2 ^ 18 - 2 ^ 22左右的东西。如果你训练一个带有L1惩罚的模型,你可以打电话 sparsify
在训练有素的模型上将其权重矩阵转换为更节省空间的格式。
我对可伸缩性的论证是,不应该使用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)
该 partial_fit()
方法是 最近 添加到 sklearn
所以希望它应该在即将发布的版本中可用(它已经在master分支中)。
问题的大小使得用神经网络解决问题变得很有吸引力。看一下 鹊,它应该比线性分类器提供更好的结果。