在R中检测文本语言

43

我有一份推文列表,我想只保留英语的那些。

我该怎么做?

7个回答

50

textcat包可以实现这一功能。它可以检测74种“语言”(更准确地说,是语言/编码组合),使用其他扩展还可以检测更多。有关详细信息和示例可在此免费获取的文章中找到:

Hornik,K.,Mair,P.,Rauch,J.,Geiger,W.,Buchta,C.和Feinerer,I. R中用于基于n-gram的文本分类的textcat软件包。《统计软件杂志》,第52期,1-17。

以下是摘要:

  

确定所使用的语言通常是大多数自然语言处理任务中的第一步。在文献中讨论的各种语言识别方法中,采用基于字符n-gram频率的Cavnar和Trenkle(1994)方法的方法尤其成功。本文介绍了基于n-gram的文本分类的R扩展包textcat,该包实现了Cavnar和Trenkle方法以及旨在消除原始方法冗余的降低n-gram方法。从Wikipedia页面中获得的多语言语料库用于说明包的功能和提供的语言识别方法的性能。

以下是其中一个示例:

library("textcat")
textcat(c(
  "This is an English sentence.",
  "Das ist ein deutscher Satz.",
  "Esta es una frase en espa~nol."))
[1] "english" "german" "spanish" 

4
textcat() 返回了许多错误分类结果:我刚刚在800篇学术论文摘要上运行了它,这些论文的语言要么是德语,要么是英语。然而,textcat 将其中3篇分类为拉丁语,3篇分类为法语(?!)和2篇分类为加泰罗尼亚语(??!)。然而,由@aykutfirat推荐的 cldr 包在所有文本上都准确无误地识别,并提出了第二和第三个备选项。 - KenHBS
8
对于一个看起来旨在快速粗略匹配(ngram 匹配)的方法来说,我认为错误率不算太高。 - geotheory

30

在之前的答案中,cldr包已不可用于CRAN且安装可能很困难。然而,Google(Chromium)的cld库现在通过其他专用包和在R中可用。

在多种欧洲语言的数千条推文测试后,我可以说,在可选项中,textcat是迄今为止最不可靠的。使用textcat时,我经常会得到错误识别为“middle_frisian”,“rumantsch”,“sanskrit”或其他不寻常语言的推文。它在其他类型的文本中可能相对较好,但我认为textcat对于推文来说相当糟糕。

cld2总体上似乎仍然优于cld3。如果您想要一个安全的方法来仅包含英语推文,您仍然可以运行和,并仅保留被两者都识别为英语的推文。

以下示例基于Twitter搜索,通常会返回许多不同语言的结果,但始终包括一些英文推文。

if (!require("pacman")) install.packages("pacman") # for package manangement
pacman::p_load("tidyverse") 
pacman::p_load("textcat")
pacman::p_load("cld2")
pacman::p_load("cld3")
pacman::p_load("rtweet")

punk <- rtweet::search_tweets(q = "punk") %>% mutate(textcat = textcat(x = text), cld2 = cld2::detect_language(text = text, plain_text = FALSE), cld3 = cld3::detect_language(text = text)) %>% select(text, textcat, cld2, cld3)
View(punk)

# Only English tweets
punk %>% filter(cld2 == "en" & cld3 == "en")

最后,如果这个问题特别涉及推文,那么我应该明确一个显而易见的事情:Twitter通过API为推文提供了自己的语言检测,并且似乎非常准确(对于非常短的推文可能理解能力稍差)。因此,如果你运行rtweet::search_tweets(q = "punk"),你会发现结果data.frame包括一个“lang”列。如果你通过API获取推文,那么你可以相信Twitter自己的检测系统比上面提到的其他解决方案更可靠(这些解决方案适用于其他文本)。


27

尝试使用http://cran.r-project.org/web/packages/cldr/,它将Google Chrome的语言检测引入了R。

#install from archive
url <- "http://cran.us.r-project.org/src/contrib/Archive/cldr/cldr_1.1.0.tar.gz"
pkgFile<-"cldr_1.1.0.tar.gz"
download.file(url = url, destfile = pkgFile)
install.packages(pkgs=pkgFile, type="source", repos=NULL)
unlink(pkgFile)
# or devtools::install_version("cldr",version="1.1.0")

#usage
library(cldr)
demo(cldr)

1
我看到这个包已经从CRAN中移除了。 - user131476
你仍然可以从http://cran.us.r-project.org/src/contrib/Archive/cldr/下载它(我没有时间进行修改以使其与CRAN的新C语言要求兼容)。 - aykutfirat
1
如果你有编译工具,你也可以使用 devtools::install_version("cldr",version="1.1.0") 来进行安装。 - aykutfirat
@aykutfirat,您能否分享一份在Ubuntu或Fedora中编译所需的库清单?或者至少是否有一些在这方面不寻常的必需包?当我尝试安装时收到的错误消息并没有提供明确的提示(至少,没有什么是我真正能够理解的)。 - giocomai
嗯... cldr::detectLanguage("Their debut album") == 100% 印度尼西亚语 - geotheory

16

在R中的一种方法是保留一个英语单词的文本文件。我有几个这样的文件,其中包括来自http://www.sil.org/linguistics/wordlists/english/的一个。在获取.txt文件后,您可以使用该文件与每个推文进行匹配。类似于:

lapply(tweets, function(x) EnglishWordComparisonList %in% x)

如果你想判断一段文本是否为英语,你需要选定一个阈值来进行截断(这里我随意选择了0.06)。

EnglishWordComparisonList<-as.vector(source(path to the list you downloaded above))

Englishinator<-function(tweet, threshold = .06) {
    TWTS <- which((EnglishWordComparisonList %in% tweet)/length(tweet) > threshold)
    tweet[TWTS]
    #or tweet[TWTS,] if the original tweets is a data frame
}

lapply(tweets, Englishinator)

我实际上没有使用过这个,因为我在研究中使用英语单词列表的方式不同,但我认为这应该可以。


1
你能进一步阐述门槛百分比吗? - jacky_learns_to_code

15
tl;dr: cld2远远比其他算法快(cld3 x22, textcat x118, 手写解决方案 x252)。
在这里,我们已经讨论了很多有关准确性的问题,对于推文来说这是可以理解的。但是速度呢?
下面是一个cld2、cld3textcat的基准测试。
我还加入了一些我自己编写的简单函数,它计算文本中停用词的出现次数(使用tm::stopwords)。
对于长文本,我认为我可能不需要复杂的算法,并且测试多种语言可能会有害。最终我的方法变得最慢了(很可能是因为打包的方式在C中循环)。
我把它放在这里,这样我就可以节省给那些有同样想法的人时间。我期望的Englishinator方案也会很慢(只测试一种语言,但要测试更多的单词和类似的代码)。
detect_from_sw <- function(text,candidates){
  sapply(strsplit(text,'[ [:punct:]]'),function(y)
    names(which.max(sapply(candidates,function(x) sum(tm::stopwords(x) %in% y))))
  )
}

基准

data(reuters,package = "kernlab") # a corpus of articles in english
length(reuters)
# [1] 40
sapply(reuters,nchar)
# [1] 1311  800  511 2350  343  388 3705  604  254  239  632  607  867  240
# [15]  234  172  538  887 2500 1030  538 2681  338  402  563 2825 2800  947
# [29] 2156 2103 2283  604  632  602  642  892 1187  472 1829  367
text <- unlist(reuters)

microbenchmark::microbenchmark(
  textcat = textcat::textcat(text),
  cld2 = cld2::detect_language(text),
  cld3 = cld3::detect_language(text),
  detect_from_sw = detect_from_sw(text,c("english","french","german")),
  times=100)

# Unit: milliseconds
# expr                 min         lq      mean     median         uq         max neval
# textcat        212.37624 222.428824 230.73971 227.248649 232.488500  410.576901   100
# cld2             1.67860   1.824697   1.96115   1.955098   2.034787    2.715161   100
# cld3            42.76642  43.505048  44.07407  43.967939  44.579490   46.604164   100
# detect_from_sw 439.76812 444.873041 494.47524 450.551485 470.322047 2414.874973   100

关于textcat不准确性的说明

我无法评论cld2cld3的准确性(@giocomai在他的答案中声称cld2更好),但我确认textcat似乎非常不可靠(在本页面的多个地方提到)。除了这篇文章被textcat分类为西班牙语外,所有方法都正确地对所有文本进行了分类:

 

"阿根廷原油产量由于1987年1月份从1986年1月份的13.81百万桶下降10.8%至12.32百万桶,石油公司Yacimientos Petroliferos Fiscales表示。1987年1月的天然气产量总计1.15亿立方米,比1986年1月的11.1亿立方米高3.6%。石油公司Yacimientos Petroliferos Fiscales补充说。路透社"


6

还有一个相当好用的R包叫做"franc"。虽然速度比其他的要慢,但我使用它的体验比cld2和特别是cld3要好。


快速比较推文显示,Franc 在检测 2000 条推文中的德语方面表现与 cld2 相当。cld3 正确地检测到了另一条推文,而 franc 和 cld2 没有检测到,但 cld3 却错过了 franc 和 cld2 准确检测到的一条德语推文。 - Simone

3

1
谢谢@Laurynas!我一直在等待一个关于R的具体答案,但是你的回答很好作为开始。然而,Google翻译API(因此www.detectlanguage.com)将于2011年12月1日停用(Google将其转换为付费服务)。 - zoltanctoth
没问题 :) 如果谷歌翻译被禁用,您可以使用detectlanguage.com上的Web服务。我今天发布了它。 - Laurynas
太好了,这很有效!我可能只是大约10个小时前检查过这个网站,那时它是基于谷歌翻译的吗? :) - zoltanctoth
是的,这个例子使用了Google翻译进行翻译(我将其移动到了http://detectlanguage.com/translate)。在您的评论之后,我创建了一个基于C语言检测器的Web服务(而不是基于Google翻译)。 - Laurynas
@Laurynas,在24小时内,detecklanguage.com网站的 web服务允许的最大请求次数是多少? - Tony Breyal

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