如何确定文档的(自然)语言?
Posted
技术标签:
【中文标题】如何确定文档的(自然)语言?【英文标题】:How to determine the (natural) language of a document? 【发布时间】:2010-11-25 21:24:33 【问题描述】:我有一组两种语言的文档:英语和德语。这些文档没有可用的元信息,程序只能查看内容。基于此,程序必须决定文档是用两种语言中的哪一种编写的。
对于这个问题,是否有任何“标准”算法可以在几个小时内实现?或者,一个可以做到这一点的免费 .NET 库或工具包?我知道LingPipe,但它是
-
Java
“半商业”用途并非免费
这个问题似乎出奇的难。我查看了Google AJAX Language API(我首先通过搜索此站点找到了它),但它非常糟糕。对于我指出的六个德语网页,只有一个猜测是正确的。其他的猜测是瑞典语、英语、丹麦语和法语......
我想出的一个简单方法是使用停用词列表。我的应用程序已经使用这样的德语文档列表,以便使用 Lucene.Net 分析它们。如果我的应用程序扫描文档以查找任何一种语言中出现的停用词,那么出现次数较多的将获胜。可以肯定的是,这是一种非常幼稚的方法,但它可能就足够了。不幸的是,我没有时间成为自然语言处理方面的专家,尽管这是一个有趣的话题。
【问题讨论】:
只需在文件中搜索“ß”、“ä”、“ë”、“ö”或“ü”字符。其他需要注意的有用关键字是“Lebensraum”、“Sauerkraut”和“Donaudampfschifffahrtsgesellschaftskapitän”,除了开玩笑,这可能是最好的解决方案。只需编制两种语言的常用词列表并测量最大的重叠。 另一个想法,在德语中,名词大写。如果您发现很多以空格开头的大写字符,那么您很可能正在查看一些德语文本。 在关于电影的英文文本中,列出了许多标题,也会有许多大写单词。在有关德国的英文新闻中,可能很容易遇到“Grundeinkommen”之类的内容。如果文本没有音译为 26 个字母,就不会出现问题。伙计们,你的把戏是行不通的。 Apache Nutch 有语言识别模块,但它是用 Java 编写的。由于模块相当独立,您可以将其从 java 转换为 C#。我以前用过java版本,感觉还不错。 这比您想象的要容易,因为您只是在比较英语和德语。只需寻找关于它们是哪些语言的明显线索 - 特殊字符、常用词等。 【参考方案1】:尝试测量文本中每个字母的出现次数。对于英语和德语文本,计算频率,也许还有它们的分布。获得这些数据后,您可能会推断出您的文本的频率分布属于哪种语言。
您应该使用贝叶斯推理来确定最接近的语言(具有一定的错误概率),或者,对于此类任务,也许还有其他统计方法。
【讨论】:
我碰巧认识一个人,他发现短的 (3-5) 个字母序列非常适合此操作。【参考方案2】:使用停用词列表的问题在于稳健性。停用词列表基本上是一组规则,每个单词一个规则。与统计方法相比,基于规则的方法对看不见的数据的鲁棒性往往较差。您将遇到的一些问题是包含相同数量的每种语言的停用词的文档、没有停用词的文档、具有来自错误语言的停用词的文档等。基于规则的方法无法执行其规则不做的任何事情t 指定。
一种不需要您自己实现朴素贝叶斯或任何其他复杂数学或机器学习算法的方法是计算字符二元组和三元组(取决于您是否有大量或少量数据可供开始 - - 二元组将使用较少的训练数据)。对少数已知源语言的文档(越多越好)进行计数,然后根据计数为每种语言构建一个有序列表。例如,英语将“th”作为最常见的二元组。拿着你的有序列表,计算你想要分类的文档中的二元组并将它们按顺序排列。然后遍历每一个,并将其在排序的未知文档列表中的位置与其在每个训练列表中的排名进行比较。为每个二元组为每种语言打分
1 / ABS(RankInUnknown - RankInLanguage + 1)
。
最终得分最高的语言为获胜者。它很简单,不需要大量编码,也不需要大量训练数据。更好的是,您可以继续向其中添加数据,并且它会有所改善。此外,您不必手动创建停用词列表,也不会因为文档中没有停用词而失败。
它仍然会被包含相等对称二元计数的文档混淆。如果您可以获得足够的训练数据,使用三元组会降低这种可能性。但是使用三元组意味着您还需要更长的未知文档。非常短的文档可能需要您减少到单个字符(unigram)计数。
说了这么多,你会遇到错误。没有灵丹妙药。组合方法并选择能够最大限度地提高您对每种方法的信心的语言可能是最明智的做法。
【讨论】:
谢谢。顺便说一句,hya 链接到一篇论文,其中包含几种语言最常见的三元组,因此我可以重复使用它(或找到这样的二元组列表),而不必计算 RankInLanguage。 有意思,我才发现这个问题和n-gram解其实是学生的练习题:umiacs.umd.edu/~resnik/cl2001/assignments/4/4a.html 酷。还有一个由印第安纳州的 Damir Cavar 编写的 Python 实现:ling.unizd.hr/~dcavar/LID,还有一些语言的数据。【参考方案3】:英语和德语使用相同的字母集,除了 ä、ö、ü 和 ß (eszett)。您可以查找这些字母以确定语言。
您还可以查看来自 Grefenstette 的此文本 (Comparing two language identification schemes)。它着眼于字母三元组和短词。德语 en_、er_、_de 的常用三元组。英语 the_, he_, the... 的常用三元组
还有 Bob Carpenter 的How does LingPipe Perform Language ID?
【讨论】:
感谢这两个链接,都很有趣。我认为 LingPipe 解决了 Grefenstette 方法的一个问题:“字符级模型特别适合语言 ID,因为它们不需要标记化输入;标记器通常是特定于语言的。”【参考方案4】:我相信标准程序是使用测试数据(即使用corpus)来衡量提议算法的质量。定义您希望算法实现的正确分析百分比,然后在您手动分类的多个文档上运行它。
至于具体算法:使用停用词列表听起来不错。据报道,另一种可行的方法是使用Bayesian Filter,例如SpamBayes。与其将其训练成火腿和垃圾邮件,不如将其训练成英语和德语。使用您的语料库的一部分,通过 spambayes 运行它,然后在完整的数据上对其进行测试。
【讨论】:
感谢您,使用贝叶斯过滤器是一个有趣的想法。不幸的是 SpamBayes 在 Python 中,我无法使用,而且我不想训练应用程序。这就是为什么我想出使用停用词的想法:统计工作已经完成并包含在列表中。 如果在英文文本中引用了德语短语,停用词将不起作用。 @Robert Petermeier,您可能需要进行一些培训。静态算法将会很糟糕。预训练的动态算法会更好,但仍然很糟糕,因为它们不会在您的域(例如您的特定类型的文档)上进行训练。没有任何“已经完成”的统计工作适用于所有场景中的每个人。【参考方案5】:语言检测在概念上并不是很困难。请查看我对related question 的回复以及对同一问题的其他回复。
如果你想尝试自己写,你应该可以在半天之内写出一个简单的检测器。我们在工作中使用了类似于以下算法的东西,并且效果出奇的好。另请阅读我链接的帖子中的python实现教程。
步骤:
为两种语言获取两个语料库并提取字符级二元组、三元组和空格分隔的标记(单词)。跟踪他们的频率。此步骤为这两种语言构建您的“语言模型”。
给定一段文本,识别每个语料库的 char bigrams、trigrams 和空格分隔的标记及其对应的“相对频率”。如果您的模型中缺少特定“特征”(char bigram/trigram 或 token),则将其“原始计数”视为 1,并使用它来计算其“相对频率”。
特定语言的相对频率的乘积给出了该语言的“分数”。这是句子属于该语言的概率的非常简单的近似。
得分较高的语言获胜。
注意 1:对于我们的语言模型中未出现的特征,我们将“原始计数”视为 1。这是因为,实际上,该特征的价值非常小,但由于我们的语料库有限,我们可能还没有遇到它。如果您将其计数为零,那么您的整个产品也将为零。为了避免这种情况,我们假设它在我们的语料库中出现为 1。这称为加一平滑。有other advance smoothing techniques。
注意 2:由于您将乘以大量分数,因此您可以轻松地运行到零。为避免这种情况,您可以在对数空间中工作并使用此等式计算您的分数。
a X b = exp(log(a)+log(b))
注意 3:我描述的算法是“Naive Bayes Algorithm”的“非常幼稚”版本。
【讨论】:
【参考方案6】:如果您想锻炼自己的编程能力并尝试自己解决问题,我鼓励您这样做;但是,如果您愿意,***是存在的。
Windows 7 内置了此功能。一个名为“扩展语言服务”(ELS) 的组件能够检测脚本和自然语言,并且它在任何 Windows 7 或 Windows Server 2008 机器上的包装盒中。取决于您是否有任何此类机器可用以及您说“免费”时的意思,这将为您完成。无论如何,这是 Google 或此处提到的其他供应商的替代品。
http://msdn.microsoft.com/en-us/library/dd317700(v=VS.85).aspx
如果你想从 .NET 访问它,这里有一些相关信息:
http://windowsteamblog.com/blogs/developers/archive/2009/05/18/windows-7-managed-code-apis.aspx
希望对您有所帮助。
【讨论】:
【参考方案7】:这两种语言的停用词方法很快,例如,通过对其他语言中不出现的德语“das”和英语中的“the”进行大量加权,可以更快地使用停用词。使用“专有词”将有助于将这种方法稳健地扩展到更大的语言组。
【讨论】:
对专有词加权的好主意,我想我会尝试一下。【参考方案8】:如果您只有两种语言(英语和德语)可供选择,问题是不是容易几个数量级?在这种情况下,您的停用词列表方法可能就足够了。
如果您向列表中添加更多语言,显然您需要考虑重写。
【讨论】:
【参考方案9】:首先,您应该对当前解决方案进行测试,看看它是否达到了您想要的准确度。在您的特定领域取得成功比遵循标准程序更重要。
如果您的方法需要改进,请尝试根据大量英语和德语语料库中的稀有度来衡量停用词的权重。或者您可以使用更复杂的技术,例如训练 Markov model 或 Bayesian classifier。您可以扩展任何算法以查看更高阶的n-grams(例如,两个或三个单词序列)或文本中的其他特征。
【讨论】:
【参考方案10】:您可以使用 Google 语言检测 API。
这是一个使用它的小程序:
baseUrl = "http://ajax.googleapis.com/ajax/services/language/detect"
def detect(text):
import json,urllib
"""Returns the W3C language code of a natural language"""
params = urllib.urlencode('v': '1.0' , "q":text[0:3000]) # only use first 3000 characters
resp = json.load(urllib.urlopen(baseUrl + "?" + params))
try:
retText = resp['responseData']['language']
except:
raise
return retText
def test():
print "Type some text to detect its language:"
while True:
text = raw_input('#> ')
retText = detect(text)
print retText
if __name__=='__main__':
import sys
try:
test()
except KeyboardInterrupt:
print "\n"
sys.exit(0)
其他有用的参考资料:
Google 宣布 API(和演示): http://googleblog.blogspot.com/2008/03/new-google-ajax-language-api-tools-for.html
Python 包装器: http://code.activestate.com/recipes/576890-python-wrapper-for-google-ajax-language-api/
另一个python脚本: http://www.halotis.com/2009/09/15/google-translate-api-python-script/
RFC 1766 定义了 W3C 语言
从以下位置获取当前语言代码: http://www.iana.org/assignments/language-subtag-registry
【讨论】:
【参考方案11】:你试过Apache Tika吗?它可以确定给定文本的语言:
http://www.dovetailsoftware.com/blogs/kmiller/archive/2010/07/02/using-the-tika-java-library-in-your-net-application-with-ikvm
我没有使用 .Net 的经验,但该链接可能会有所帮助。如果你可以在你的环境中执行一个 jar,试试这个:
java -jar tika-app-1.0.jar -l http://www.admin.ch/
输出:
de
希望对您有所帮助。
【讨论】:
以上是关于如何确定文档的(自然)语言?的主要内容,如果未能解决你的问题,请参考以下文章