将文档分类为类别

时间:2010-06-24 19:56:42

标签: python machine-learning nlp nltk naivebayes

我在Postgres数据库中存储了大约300k个文档,这些文档被标记了主题类别(总共大约有150个类别)。我有另外150k文件还没有类别。我正在尝试找到以编程方式对它们进行分类的最佳方法。

我一直在探索NLTK及其朴素贝叶斯分类器。似乎是一个很好的起点(如果你能为这项任务建议一个更好的分类算法,我会全力以赴)。

我的问题是我没有足够的RAM来同时训练所有150个categoies / 300k文件上的NaiveBayesClassifier(5个类别的培训使用8GB)。此外,随着我​​在更多类别上的训练,分类器的准确性似乎下降(2个类别的准确率为90%,5%时为81%,10个为61%)。

我是否应该一次只训练5个类别的分类器,并通过分类器运行所有150k文件以查看是否有匹配?看起来这样可行,除了会有很多误报,其中没有真正匹配任何类别的文档因为它是可用的最佳匹配而被分类器打开了...是否存在如果文档不适合任何类别,为分类器设置“无上述”选项的方法是什么?

这是我的测试班http://gist.github.com/451880

3 个答案:

答案 0 :(得分:33)

您应该首先将文档转换为TF-log(1 + IDF) vectors:术语频率稀疏,因此您应该使用python dict,其中term作为键并计为值,然后除以总计数以获得全局频率。

另一种解决方案是使用abs(hash(term))作为正整数键。然后你使用scipy.sparse向量比python dict更方便,更有效地执行线性代数运算。

还通过平均属于同一类别的所有标记文档的频率来构建150个频率向量。然后,对于要标记的新文档,您可以计算文档向量和每个类别向量之间的cosine similarity,并选择与文档标签最相似的类别。

如果这还不够好,那么你应该尝试使用this examplescikit-learn中所解释的使用L1惩罚训练逻辑回归模型(这是liblinear的包装,如@ephes所解释的)。用于训练逻辑回归模型的向量应该是先前引入的TD-log(1 + IDF)向量,以获得良好的性能(精确度和召回率)。 scikit learn lib提供了一个sklearn.metrics模块,其中包含计算给定模型和给定数据集的分数的例程。

对于较大的数据集:您应该尝试vowpal wabbit,这可能是地球上最快的兔子,因为大规模的文档分类问题(但不容易使用python包装器AFAIK)。

答案 1 :(得分:11)

您的文件有多大(字数)? 150k trainingdocs的内存消耗应该不是问题。

朴素贝叶斯是一个不错的选择,特别是当你有很多类别,只有少数训练样例或非常嘈杂的训练数据。但总的来说,线性支持向量机确实表现得更好。

您的问题多类(文档仅属于一个类别)或多标记(文档属于一个或多个类别)?

准确性是判断分类器性能的不良选择。您应该使用精确与召回,精确召回盈亏平衡点(prbp),f1,auc并且必须查看精确与召回曲线,其中召回(x)根据您的置信度阈值对精度(y)绘制(文件是否属于某一类别)。通常,您将为每个类别构建一个二元分类器(一个类别的正面训练示例与不属于您当前类别的所有其他训练示例)。您必须为每个类别选择最佳置信度阈值。如果您希望将每个类别的单个度量值组合到全局性能度量中,则必须微观(总结所有真阳性,误报,漏报和真阴性以及计算综合得分)或宏(每个类别的计算得分和然后平均所有类别的平均分数。

我们拥有数千万份文档,数百万个培训示例和数千个类别(多标签)。由于我们面临严重的培训时间问题(每天新增,更新或删除的文档数量非常高),我们使用liblinear的修改版本。但是对于使用liblinear(liblinear2scipyscikit-learn周围的python包装器之一的小问题,应该可以正常工作。

答案 2 :(得分:2)

  

有没有办法让“没有   以上“分类器的选项   如果文件不适合   任何类别?

您可能只是通过每次训练“无上述”伪类别来获得此效果。如果你可以训练的最大值是5个类别(虽然我不确定为什么它会占用相当多的RAM),从每个实际的2K文档中训练4个实际类别,并且用2K文档训练“以上都没有”的类别从所有其他146个类别中随机抽取(如果你想要“分层抽样”的方法,则每个类别大约13-14个,这可能是更健全的。)

仍然感觉有点像kludge,你可能会采用一种完全不同的方法 - 找到一个多维的doc度量,将你的300K预先标记的文档定义为150个可合理分离的集群,然后只分配每个如此确定的其他尚未标记的文档到适当的集群。我不认为NLTK有任何可以直接支持这种事情的东西,但是,嘿,NLTK一直在快速增长,以至于我可能错过了一些东西......; - )