2010-06-24 70 views
29

我已经有大约300k个文档存储在Postgres数据库中,并且标记了主题类别(共有大约150个类别)。我还有另外150k文件还没有分类。我试图找到对它们进行编程分类的最佳方法。将文档分类为

我一直在探索NLTK及其朴素贝叶斯分类器。看起来像一个很好的起点(如果你可以提出一个更好的分类算法来完成这项任务,我就会全神贯注)。

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

我应该一次只训练5个类别的分类器,并通过分类器运行所有150k文档以查看是否有匹配?看起来这样会起作用,除非会有很多误报,其中文档与任何类别都不匹配的文档只是因为它是可用的最佳匹配才会被分类器使用。只有在文档不适合任何类别的情况下,才能为分类器提供“以上都不是”选项?

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

+0

也许一个在线/增量培训模式将解决记忆问题:http://en.wikipedia.org/wiki/Online_machine_learning – Amro 2010-06-25 20:45:11

回答

30

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

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

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

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

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

+2

Vowpal wabbit速度很快。但是我们仍然使用批量训练而不是在线学习算法,因为liblinear(正确优化)只需几分钟就可以处理数百万个文档(我们对特征向量进行了缩放(共享),以便新的训练或分类过程不必解析但只能遍历主内存),它的性能更好(我现在没有数字......)。 – ephes 2010-06-24 22:13:42

+2

同意,vowpal wabbit在数据流无限且不再适合内存时非常有趣,例如当来自流行的网络邮件提供商的“报告垃圾邮件”按钮:) – ogrisel 2010-06-24 22:19:17

+2

除此之外......质心分类并不比朴素贝叶斯好得多。这篇文章http://www2009.org/proceedings/pdf/p201.pdf是错误的。我们告诉他们,他们使用测试数据进行培训(由于错误),但讨论没有进行......线性SVM仍然是最先进的。 – ephes 2010-06-24 22:19:52

2

有没有办法有一个选项分类“的 以上都不是”刚 的情况下,该文件不适合 任何类别的?

只要每次都训练一个“以上都不是”的伪类别,就可能会产生这种效果。如果你可以训练的最大值是5类(尽管我不确定它为什么会吃掉相当多的RAM),那么从它们的实际2K文档中分别训练出4个实际的类别,并且在它们的2K文档中“没有上述”从所有其他146个类别中随机抽取(如果您想采用“分层抽样”方法,可能会更加稳定),每个类别大约13-14个。

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

+0

我们有一个特殊类别的文件,我们知道我们无法正确分类。这有点混杂,但效果很好。 – ephes 2010-06-24 20:51:38

11

有多大(单词数)你的文件是?内存消耗在150K trainingdocs不应该是一个问题。

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

是你的问题多类(一个文件只属于一个类别)还是多标签(一个文件属于一个或多个类别)?

准确度是判断分类器性能的一个糟糕的选择。您应该使用精确度与回忆率,精确回忆平衡点(prbp),f1,auc,并且必须查看基于您的置信度阈值的值绘制召回(x)与精度(y)的精度vs回忆曲线(文件是否属于某个类别)。通常情况下,您将为每个类别构建一个二元分类器(一个类别的正面训练示例与不属于您当前类别的所有其他训练示例)。您必须选择每个类别的最佳置信度阈值。如果要将每个类别的单个度量结合到一个全局性能度量中,则必须微调(总结所有真正的肯定结果,假阳性结果,假阴性结果和真阴性结果以及计算结合得分)或宏观结果(每个类别的计算结果分数和然后平均所有类别的这些分数)平均值。

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

+0

平均文档大约500-1000字。 这些文件可以是“多标签”。 – erikcw 2010-06-24 22:07:16

+1

好的,然后去@grorisel(我忘了提及)建议的稀疏tfidf向量和每个类别一个二进制分类器。也许你在文档中有一些非序号(数字)特征 - 你必须适当地装入它们。 – ephes 2010-06-24 23:26:04

+0

您使用的是liblinear的修改版本吗?或者你自己修改了什么? – 2010-06-24 23:58:10