我在Postgres数据库中存储了大约30万份文档,这些文档都标注了主题类别(总共有大约150个类别)。我还有另外15万份文档尚未分类。我正在寻找最佳的程序化方法来对它们进行分类。
我一直在探索NLTK及其朴素贝叶斯分类器。这似乎是一个不错的起点(如果你能推荐更适合此任务的分类算法,我很乐意听取)。
我的问题是,我没有足够的RAM来一次性对所有150个类别/30万份文档进行朴素贝叶斯分类器的训练(训练5个类别就用了8GB)。此外,随着训练类别的增加,分类器的准确性似乎在下降(2个类别的准确率为90%,5个类别为81%,10个类别为61%)。
我是否应该一次训练5个类别的分类器,然后让所有15万份文档通过分类器,看看是否有匹配的?这似乎可行,但可能会有很多误报,即那些实际上不符合任何类别的文档被强行归入某个类别,因为这是可用的最佳匹配…有没有办法让分类器有一个“以上皆非”的选项,以防文档不适合任何类别?
这是我的测试类 http://gist.github.com/451880
回答:
你应该首先将你的文档转换为TF-log(1 + IDF)向量:词频是稀疏的,所以你应该使用python字典,以词为键,以计数为值,然后除以总计数来获得全局频率。
另一种解决方案是使用abs(hash(term))作为正整数键。例如,然后你可以使用scipy.sparse向量,这比python字典更方便且更有效地执行线性代数操作。
此外,通过平均属于同一类别的所有标记文档的频率,构建150个频率向量。然后,对于要标记的新文档,你可以计算文档向量与每个类别向量之间的余弦相似度,并选择最相似的类别作为文档的标签。
如果这还不够好,那么你应该尝试使用L1惩罚训练一个逻辑回归模型,如这个例子中所解释的scikit-learn(这是对liblinear的包装,如@ephes所解释)。用于训练逻辑回归模型的向量应该是之前介绍的TD-log(1+IDF)向量,以获得良好的性能(精确度和召回率)。scikit learn库提供了一个sklearn.metrics模块,其中包含计算给定模型和给定数据集的这些分数的例程。
对于更大的数据集:你应该尝试vowpal wabbit,这可能是地球上处理大规模文档分类问题最快的兔子(但据我所知,Python包装器并不容易使用)。