跳转到主要内容

通过语言处理进行内容分类/聚类

项目描述

简介

collective.classification旨在提供一套用于自动文档分类的工具。目前它使用自然语言工具包,并具有基于词性标注(POS)的文档分类器,深受topia.termextract的影响。此产品主要用于实验和开发。目前支持英语和荷兰语。

这一切都是关于什么的?

这主要关乎乐趣!该软件包处于非常早期的实验阶段,并热切期待贡献。您可以通过查看测试来了解哪些功能有效或无效。您也可能能够用它做一些有用的事情。

1) 可以执行术语提取,以快速了解文档的内容。2) 在内容丰富、标签众多(或称“主题”在plone语言中)的大型网站上,为新内容分配标签可能很困难。在这种情况下,一个训练有素的分类器可以为负责标记内容的编辑提供有用的建议。3) 可以根据术语相似性找到类似文档。4) 聚类可以帮助您将未分类的内容组织成组。

它是如何工作的?

目前存在以下类型的实用工具

  • 词性标注器,用于将文档中的词语分类为词性。目前提供了两个,一个是Penn TreeBank标注器,另一个是三元组标注器。两者都可以使用除了英语以外的其他语言进行训练,这正是我们在这里所做的工作。

  • 术语提取器,负责从某些文档中提取重要术语。我们这里使用的提取器假设在文档中只有名词是重要的,并使用词性标注器来找到文档中最常用的名词。有关详细信息,请参阅代码和测试。

  • 内容分类器,可以将内容标记为预定义的分类。这里,使用了一个朴素贝叶斯分类器。基本上,分类器查看已经标记的内容,执行术语提取,并使用术语和标签作为输入来训练自己。然后,对于新内容,分类器将根据内容提取的术语提供标签建议。

  • 根据提取的术语找到类似内容的实用工具。

  • 聚类器,可以在没有内容分类先验知识的情况下,根据特征相似性将内容分组。目前使用的是NLTK的k-means聚类器。

安装与设置

在运行buildout之前,请确保已安装yaml及其Python绑定(在OSX上使用macports,或在Linux上使用您的包安装程序)。如果您的操作系统上存在nltk,您也可以安装它,否则它将在运行buildout时被获取。

要开始使用,您只需将包添加到“eggs”部分,并运行buildout,重新启动Plone实例,并使用快速安装程序或通过“站点设置”中的“附加产品”部分安装“collective.classification”包。

警告:首次安装时,将从NLTK的存储库获取语言数据并将其存储在您的文件系统上本地。它并不大(约400kb),但需要plone用户有权访问其“家”。运行测试还将从nltk获取更多数据,总大小约为225Mb,所以不是为磁盘空间小的人准备的。

如何使用它?

  • 对于已解析的文档,您可以调用术语视图来显示已识别的术语(只需将@@terms附加到内容的URL后即可调用视图)。

  • 为了使用分类器并为某些内容获取建议标签,您可以在内容上调用@@suggest-categories。这相当于在浏览器中附加@@suggest-categories到URL。将出现一个表单,提供建议,选择看起来合适的,并应用。您需要有权编辑文档才能调用视图。

  • 您可以根据其术语找到某些内容的类似内容,通过调用@@similar-items视图。

  • 对于聚类,您只需从任何地方调用@@clusterize视图。结果不是确定性的,但希望能有所帮助;)。您需要管理员权限才能进行此操作,以免允许您的用户对您的站点进行DDoS攻击!

集成测试

在这里,我们将使用布朗语料库的样本测试分类器。布朗语料库包含一系列带有词性标注的英语文章,这些文章也被方便地分类。测试包括使用每个类别(新闻、社论和爱好)中的20篇文章来训练分类器。然后我们将要求分类器对每个类别中的5篇文章进行分类,看看会发生什么。

现在我们可以开始添加文档,从布朗语料库中按类别“新闻”分类的前20篇文档开始。

>>> from nltk.corpus import brown
>>> for articleid in brown.fileids(categories='news')[:20]:
...     text = " ".join(brown.words(articleid))
...     id = self.folder.invokeFactory('Document',articleid,
...                                    title=articleid,
...                                    text=text,
...                                    subject='news')

接着是按类别“社论”分类的20篇文档

>>> for articleid in brown.fileids(categories='editorial')[:20]:
...     text = " ".join(brown.words(articleid))
...     id = self.folder.invokeFactory('Document',articleid,
...                                    title=articleid,
...                                    text=text,
...                                    subject='editorial')

最后是按类别“爱好”分类的20篇文档

>>> for articleid in brown.fileids(categories='hobbies')[:20]:
...     text = " ".join(brown.words(articleid))
...     id = self.folder.invokeFactory('Document',articleid,
...                                    title=articleid,
...                                    text=text,
...                                    subject='hobbies')

所有这些文档都应该被解析并索引

>>> catalog = self.folder.portal_catalog
>>> sr = catalog.searchResults(noun_terms='state')
>>> len(sr) > 5
True

让我们看看第一个“社论”内容中我们得到了哪些术语

>>> browser = self.getBrowser()
>>> browser.open(self.folder.absolute_url()+'/cb01/@@terms')
>>> browser.contents
'...state...year...budget...war...danger...nuclear war...united states...'

核战争和美国?令人恐惧的事情……现在是训练分类器的时候了

>>> from zope.component import getUtility
>>> from collective.classification.interfaces import IContentClassifier
>>> classifier = getUtility(IContentClassifier)
>>> classifier.train()
>>> classifier.tags()
['editorial', 'hobbies', 'news']

首先,当被询问已分类的文本时,分类器应该相当确信

>>> browser.open(self.folder.absolute_url()+'/ca01/@@suggest-categories')
>>> browser.contents
'...news 100.0%...editorial 0.0%...hobbies 0.0%...'

所以让我们看看这会带我们到哪儿,通过要求分类器对5篇我们知道类别的更多文档进行分类。我们将直接使用分类器的函数,而不是将文档添加到plone并调用@@suggest-categories视图。首先是“新闻”

>>> classificationResult = []
>>> for articleid in brown.fileids(categories='news')[20:25]:
...     text = " ".join(brown.words(articleid))
...     id = self.folder.invokeFactory('Document',articleid,
...                                    text=text)
...     uid = self.folder[id].UID()
...     classificationResult.append(classifier.classify(uid))
>>> classificationResult
['news', 'news', 'news', 'news', 'news']

让我们看看我们对“社论”的表现如何

>>> classificationResult = []
>>> for articleid in brown.fileids(categories='editorial')[20:25]:
...     text = " ".join(brown.words(articleid))
...     id = self.folder.invokeFactory('Document',articleid,
...                                    text=text)
...     uid = self.folder[id].UID()
...     classificationResult.append(classifier.classify(uid))
>>> classificationResult
['editorial', 'editorial', 'editorial', 'editorial', 'editorial']

太棒了!关于“爱好”呢?

>>> classificationResult = []
>>> for articleid in brown.fileids(categories='hobbies')[20:25]:
...     text = " ".join(brown.words(articleid))
...     id = self.folder.invokeFactory('Document',articleid,
...                                    text=text)
...     uid = self.folder[id].UID()
...     classificationResult.append(classifier.classify(uid))
>>> classificationResult
['hobbies', 'hobbies', 'editorial', 'hobbies', 'hobbies']

还不错!总的来说:我们对了14/15个…

现在让我们再次选择第一个社论项目,并根据我们提取的术语查看哪些文档与它相似

>>> browser.open(self.folder['cb01'].absolute_url()+'/@@similar-items')

最相似的条目(Jaccard指数约为0.2)是cb15

>>> browser.contents
'...cb15...0.212121212121...'

让我们看看它们的共同术语是什么

>>> cb01terms = catalog.searchResults(
... UID=self.folder['cb01'].UID())[0].noun_terms[:20]
>>> cb15terms = catalog.searchResults(
... UID=self.folder['cb15'].UID())[0].noun_terms[:20]
>>> set(cb01terms).intersection(set(cb15terms))
set(['development', 'state', 'planning', 'year', 'area'])

这是可以接受的,因为两篇文档都谈论发展和预算规划…

关于统计信息呢?我们可以调用@@stats视图来找出…

>>> self.setRoles('Manager')
>>> browser.open(self.folder.absolute_url()+'/@@classification-stats')
>>> browser.contents
'...state...True...editorial:hobbies...5.0...'

这基本上告诉我们,如果单词“国家”存在,分类器给出5比1的概率,内容属于“社论”类别而不是“爱好”类别

0.1b2

  • 完全删除了持久的名词存储。现在名词和名词短语术语直接存储在目录中,使用plone.indexer。[ggozad, stefan]

  • 使用BTrees代替PersistentDict。应该会使ZODB的写入更轻量。[ggozad]

  • 名词短语语法和规范化现在成为语言相关标记器的属性。[ggozad]

  • 删除了大量的控制面板功能。不需要混淆。[ggozad]

  • 修复了荷兰语言支持。[ggozad]

0.1b1

  • 通过不再利用PenTreeBank标记器,提高了速度。[ggozad]

  • 添加了多语言支持,从荷兰开始![ggozad]

  • 不再需要下载所有语料库了。[ggozad]

  • 大量重构。东西被移动,并删除了大量不必要的代码。[ggozad]

  • 我们现在使用一个预训练的Brill/Trigram/Affix标记器。这使得collective.classification能够在不包含所有语料库的情况下发货。如果需要,用户仍可以提供不同的标记器。[ggozad]

  • 默认的nltk PenTreeBank标记器不再使用。太慢了。[ggozad]

  • npextractor不再是一个本地持久性实用程序。选择了全局非持久性对象。[ggozad]

  • 现在使用zope.lifecycle事件。[ggozad]

  • 与plone 4兼容。[ggozad]

0.1a3

  • 引入了IClassifiable接口。ATContentTypes现在适应了它,应该更容易添加其他非AT内容类型或自定义适配器。[ggozad]

  • 处理IObjectRemovedEvent事件。[ggozad]

  • 添加了一个表单,用于从布朗语料库导入样本内容,用于调试和测试。[ggozad]

  • 添加了一些统计信息,通过@@classification-stats。显示了解析的文档数以及最有用的术语。[ggozad]

  • 添加了@@terms视图,允许用户检查某些内容的识别术语。[ggozad]

  • 在训练n-gram标记器时必须指定语料库类别。修复#3 [ggozad]

0.1a2

  • 使控制面板更合理。修复#1。[ggozad]

  • NP-extractor已成为本地持久性实用程序。[ggozad]

  • 将 @@subjectsuggest 重命名为 @@suggest-categories。修复 #2。[ggozad]

  • “memoized”术语提取器。[ggozad]

  • 向控制面板添加了友好的类型。[ggozad]

  • 更新了文档和依赖项,以警告关于yaml。[ggozad]

0.1a1

  • 首次公开发布。[ggozad]

项目详情


下载文件

下载适用于您的平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源分布

collective.classification-0.1b2.zip (526.3 kB 查看哈希)

上传时间

支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面