data.table在设置键时如何对字符串进行排序

时间:2013-08-20 13:27:11

标签: r data.table

昨天我不得不花一些时间试图在我的代码中找到一个错误,我发现data.table包以一种与base不同的方式对字符串进行排序。这是一种正常的行为吗?最有效的方式(有data.table的好处)来重现使用基本order函数获得的结果是什么?这是一个可重复玩具的例子:

library(data.table)
options(stringsAsFactors = FALSE)

d <- data.frame(cn=c("USA","Ubuntu","Uzbekistan"))
d[order(d$cn),,drop=F]

#          cn
#2     Ubuntu
#1        USA
#3 Uzbekistan

dt <- data.table(d)
setkey(dt, cn)
dt

#           cn
#1:        USA
#2:     Ubuntu
#3: Uzbekistan

options(stringsAsFactors = default.stringsAsFactors())

OS Windows 7

2 个答案:

答案 0 :(得分:10)

2014年3月更新

对此有一些争论。从v1.9.2开始,我们现在已经使用C语言环境进行了setkey排序。例如,所有大写字母都在所有小写字母之前,而不管用户的语言环境如何。这是在v1.8.8中做出的改变,我们原本打算改变,但现在仍然坚持。

考虑save() - 您的语言环境中的键控表和同事load() - 在不同的语言环境中使用它。当他们加入该表时,如果它是区域设置排序顺序,它可能不再正常工作。如果setkey允许再次进行区域设置排序,我们必须更仔细地考虑,可能是通过保存区域设置名称和“已排序”属性,因此data.table至少可以比较和检测当前区域设置与运行setkey的区域设置不同。

这也是出于速度原因,因为根据区域设置进行排序比C语言环境慢得多。虽然,我们可以尽可能高效地完成它,并允许它可选地是理想的。

因此,现在这是一个功能请求,非常欢迎进一步的评论。

FR#4842 setkey to sort using session's locale not C locale



好的抓住!拨打setkey的电话会调用setkeyv,并调用fastorder来“排序”依次调用chorder的列/条目。

chorder又调用C函数Ccountingcharacter.c。现在,我想这个问题是由于“语言环境”造成的。

让我们看看我的Mac上的“语言环境”。

Sys.getLocale()
# [1] "en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8"

现在让我们看看order如何对其进行排序:

x <- c("USA", "Ubuntu", "Uzbekistan")
order(x)
# [1] 2 1 3

现在,让我们将“locale”更改为“C”。

Sys.setlocale("LC_ALL", "C")
# [1] "C/C/C/C/C/en_US.UTF-8"

order(x)
# [1] 1 2 3

来自?order

  

字符向量的排序顺序取决于正在使用的语言环境的整理顺序:请参阅Comparison

来自?Comparison

  

字符向量中字符串的比较是使用正在使用的语言环境的整理顺序在字符串中进行词典编写:请参阅locales。诸如en_US的语言环境的整理顺序通常不同于C(应该使用ASCII)并且可能令人惊讶。谨防对整理顺序做出任何假设:例如在爱沙尼亚语Z中介于S和T之间,并且整理不一定是逐个字符的 - 在丹麦语中作为单个字母排序,在z之后.......

因此,基本上,order以及“C”区域设置提供与data.table的{​​{1}}相同的顺序。我的猜测是setkey调用的C函数自动在C语言环境中运行,它将比较“S”在“b”之前的ascii值。

将这一点引入@ MatthewDowle的注意力可能很重要(如果他还没有意识到的话)。所以,我建议您将其归档为错误here(只是为了确定)。

答案 1 :(得分:2)

好吧,我不确定最有效的方法是什么,但您可以执行以下操作来重现data.frame结果。

dt[order(dt$cn)]

           cn
1:     Ubuntu
2:        USA
3: Uzbekistan