如何确定文档的(自然)语言?

23
我有一组包含英语和德语的文档,没有可用的元信息,程序只能查看内容。基于此,程序必须决定文档是使用哪种语言编写的。是否有此问题的“标准”算法可以在几小时内实现?或者,是否有一个免费的.NET库或工具包可以做到这一点?我知道LingPipe,但它是Java的,并且对于“半商业”使用不是免费的。这个问题似乎非常难。我检查了Google AJAX Language API(我首先通过搜索此网站找到它),但它非常糟糕。对于我指向的六个德语网页,它只有一个正确的猜测。其他猜测是瑞典语、英语、丹麦语和法语... 一个我想出的简单方法是使用停用词列表。我的应用程序已经使用这样的列表来分析Lucene.Net中的德语文档。如果我的应用程序扫描文档以查找来自任何一种语言的停用词的出现,那么出现次数更多的语言将获胜。这是一个非常天真的方法,但它可能足够好。不幸的是,我没有时间成为自然语言处理方面的专家,尽管这是一个引人入胜的主题。

6
只需在文件中搜索“ß”、“ä”、“ë”、“ö”或“ü”字符。其他有用的关键词包括“Lebensraum”、“Sauerkraut”和“Donaudampfschifffahrtsgesellschaftskapitän”。开玩笑的话不说了,最好的解决方案可能是编制一个共同词汇列表,然后测量最大的重叠部分。 - David Rutten
另一个想法,在德语中,名词的首字母是大写的。如果你发现有很多前面有空格的大写字符,很可能你正在查看一些德语文本。 - David Rutten
1
在一篇关于电影的英文文章中,列出了许多电影标题,因此也会有很多大写字母。在关于德国的英文新闻中,可能会轻易地遇到"Grundeinkommen"这样的词汇。如果这段文字没有被转录成26个字母的字母表,这个问题就不会被提出。伙计们,你们的把戏行不通。 - P Shved
1
Apache Nutch有一个语言识别模块,但它是用Java编写的。由于该模块相对独立,您可以将其从Java转换为C#。我过去使用过Java版本,并发现它非常好用。 - Shashikant Kore
这比你想象的要容易,因为你只需要比较英语和德语。只需寻找明显的线索,例如特殊字符、常用词等即可。 - Cam
可以使用命名实体识别技术。请参考 https://en.wikipedia.org/wiki/Named-entity_recognition。 - Sayali Sonawane
11个回答

6

尝试测量文本中每个字母的出现次数。对于英语和德语文本,计算频率和分布。获得这些数据后,您可以推断出您的文本频率分布所属的语言。

您应该使用贝叶斯推断来确定最接近的语言(具有一定的误差概率),或者可能有其他统计方法可用于此类任务。


1
我碰巧认识一个人,他发现短(3-5)个字母的序列非常适用于这个。 - BCS

6
使用停用词列表的问题在于其鲁棒性。停用词列表基本上是一组规则,每个词一个规则。基于规则的方法往往对未见过的数据不够强健而无法处理包括以下问题的文档: 含有同等数量来自每种语言的停用词的文档、没有停用词的文档、含有错误语言停用词的文档等。基于规则的方法不能做超出其规则限制之外的事情。
一种不需要你自己实现朴素贝叶斯或任何其他复杂的数学或机器学习算法的方法是计算字符二元组和三元组(根据你的训练数据量,二元组可以用于少量训练数据)。对已知来源语言的一些文件(越多越好)进行计数,然后根据计数构建每种语言的有序列表。例如,英语中"th"是最常见的二元组。有了你手头的有序列表,计算要分类的文档中的二元组并按顺序排列。然后逐个比较其在排序未知文档列表中的位置与在每个训练列表中的排名。为每种语言的每个二元组打分: 1 / ABS(RankInUnknown - RankInLanguage + 1)
得分最高的语言是获胜者。这很简单,不需要大量编程,也不需要大量训练数据。更好的是,您可以随时添加数据并使其变得更好。此外,您不必手动创建停用词列表,并且它不会因文档中没有停用词而失败。
它仍然可能被包含相等对称二元组计数的文档所困惑。如果你能获得足够的训练数据,使用三元组将使这种情况变得不太可能发生。但是使用三元组意味着您还需要未知文档更长。非常短的文档可能需要您降低到单字符(单元组)计数。
所有这些都说了,你仍然会有错误。没有银弹。结合方法并选择在每种方法中最大化你的信心的语言可能是最明智的事情。

谢谢你。顺便说一句,hya提供了一个包含多种语言中最常见的三元组的论文,所以我可以重复使用它(或者找到一个大量二元组的列表),这样就不用计算RankInLanguage了。 - Robert Petermeier
有趣的是,我刚刚发现这个问题和n-gram解决方案实际上是学生练习:http://www.umiacs.umd.edu/~resnik/cl2001/assignments/4/4a.html - Robert Petermeier
很好。Indiana的Damir Cavar还提供了Python实现:http://ling.unizd.hr/~dcavar/LID/,同时也提供了一些语言的数据。 - ealdent

5

除了ä、ö、ü和ß(eszett)外,英语和德语使用相同的字母集。您可以寻找这些字母来确定语言。

您还可以查看Grefenstette的此文本(比较两种语言识别方案)。它查看字母三元组和短单词。德语常见的三元组是en_、er_、_de。英语常见的三元组是the_、he_、the...

还有Bob Carpenter的LingPipe如何执行语言标识?


1
谢谢提供这两个链接,都非常有趣。我认为LingPipe的链接解决了Grefenstette方法中的一个问题:“字符级模型特别适用于语言识别,因为它们不需要标记化输入;分词器通常是语言特定的。” - Robert Petermeier

4

语言检测在概念上并不是很困难。请查看我对一个相关问题的回答以及其他对同一问题的回复。

如果你想自己尝试编写,你应该能够在半天内编写一个简单的检测器。我们在工作中使用类似以下算法的东西,它的效果出奇的好。还要阅读我链接的文章中的python实现教程。

步骤

  1. 取两种语言的文本并提取字符级别的二元组、三元组和以空格分隔的标记(单词)。跟踪它们的频率。这一步构建了两种语言的“语言模型”。

  2. 给定一段文本,识别每个语料库中的字符二元组、三元组和以空格分隔的标记及其相应的“相对频率”。如果模型中缺少特定的“特征”(字符二元组/三元组或标记),则将其“原始计数”视为1,并用来计算其“相对频率”。

  3. 特定语言的相对频率的乘积给出该语言的“得分”。这是一个非常天真的近似,表示该句子属于该语言的概率。

  4. 得分更高的语言获胜。

注意1:对于我们语言模型中不存在的特征,我们将“原始计数”视为1。这是因为在现实中,该特征的值非常小,但由于我们有限的语料库,可能尚未遇到它。如果您将其计数为零,则整个乘积也将为零。为了避免这种情况,我们假设它在我们的语料库中出现一次。这被称为加一平滑。还有其他先进的平滑技术
注意2:由于您将乘以大量分数,很容易变成零。为了避免这种情况,您可以在对数空间中工作,并使用此方程式来计算您的分数。
                a X b =  exp(log(a)+log(b))

注意3:我描述的算法是“非常朴素”的“朴素贝叶斯算法”版本。

3
如果您想要通过自己解决问题来展示编程能力,我鼓励您这样做;然而,如果您愿意使用现成的工具,那么这个“轮子”已经存在了。
Windows 7自带此功能。一个名为“扩展语言服务”(ELS)的组件可以检测脚本和自然语言,它在任何Windows 7或Windows Server 2008机器上都可以使用。根据您是否有这样的机器可用以及您所说的“免费”是什么意思,这将为您完成任务。无论如何,这是谷歌或其他供应商提到的替代方案。

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

希望有所帮助。

3
我认为标准的过程是使用测试数据(即语料库)来测量所提算法的质量。定义算法需要达到的正确分析百分比,然后将其运行于一些手动分类过的文档中。
至于具体算法:使用停用词列表听起来不错。另一种被报道有效的方法是使用贝叶斯过滤器,例如SpamBayes。不要将其训练成垃圾邮件和正常邮件,而是训练成英文和德文。使用一部分语料库,通过SpamBayes运行,然后在完整数据上进行测试。

谢谢你的建议,使用贝叶斯过滤器是一个有趣的想法。不幸的是,SpamBayes 是用 Python 编写的,而我不能使用它,而且我也不想训练应用程序。这就是为什么我想到使用停用词的想法:统计工作已经完成,并包含在列表中。 - Robert Petermeier
停用词在英文文本中引用德语短语时无效。 - P Shved
@Robert Petermeier,你可能需要进行一些训练。静态算法会非常糟糕。预先训练的动态算法会更好,但仍然不够好,因为它们没有在你的领域(例如你特定类型的文档)上进行训练。没有任何已经完成的统计工作可以适用于所有情况。 - Cerin

2

对于这两种语言的停用词方法是快速的,通过对不出现在另一种语言中的单词进行加重,例如德语中的“das”和英语中的“the”,可以使其更快。使用“独占性词语”将有助于在更大的语言群体中强有力地推广此方法。


好主意给独占词加权,我想我会尝试一下。 - Robert Petermeier

1

你可以使用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


1

如果你只需要选择两种语言(英语和德语),那么问题不是容易了几个数量级吗?在这种情况下,你的停用词列表方法可能已经足够好了。

显然,如果你添加更多语言到你的列表中,你需要考虑重写。


1

首先,您应该设置一个测试来检查您当前的解决方案是否达到了您期望的准确度水平。在您特定领域的成功比遵循标准程序更重要。

如果您的方法需要改进,可以尝试通过在大型英语和德语语料库中的稀有性来加权您的停用词。或者您可以使用更复杂的技术,如训练马尔可夫模型贝叶斯分类器。您可以扩展任何算法以查看更高阶的n-gram(例如,两个或三个单词序列)或文本中的其他特征。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接