为什么这段代码:as.factor(c("\U201C", '"3', "1", "2", "\U00B5")),会在每个操作系统上返回不同的因子级别排序?
在Linux上:
> as.factor(c("\U201C",'"3', "1", "2","\U00B5")) [1] " "3 1 2 µ Levels: µ " 1 2 "3
在Windows上:
> as.factor(c("\U201C",'"3', "1", "2","\U00B5")) [1] " "3 1 2 µ Levels: "3 " µ 1 2
在Mac OS上:
>as.factor(c("\U201C",'"3', "1", "2","\U00B5")) [1] " "3 1 2 µ Levels: "3 " 1 2 µ
我让一些学生提交了一个包含as.numeric(as.factor(dat$var))的RMardkown作业。现在承认这不是一种好的编码方式,但输出中的不一致会导致很多混乱和浪费时间。
发布于 2016-09-06 10:07:54
它不只是Unicode,也不只是R;sort通常(甚至在*nix命令sort中)可以是特定于地区的。为了消除差异,需要在所有机器上通过Sys.setlocale (根据@alistaire的评论)设置LC_COLLATE (假设为"C")。
对我来说,在Windows (7)上:
sort(c("Abc", "abc", "_abc", "ABC"))
[1] "_abc" "abc" "Abc" "ABC" 而在Linux上(Ubuntu 12.04 ...哇,我需要升级那台机器)我得到
sort(c("Abc", "abc", "_abc", "ABC"))
[1] "abc" "_abc" "Abc" "ABC" 按照上面的方式设置区域设置
Sys.setlocale("LC_COLLATE", "C")给出
sort(c("Abc", "abc", "_abc", "ABC"))
[1] "ABC" "Abc" "_abc" "abc" 在两台机器上,完全相同。
sort的*nix man页面给出了粗体警告
\*\*\* WARNING \*\*\* The locale specified by the environment affects sort order. Set LC\_ALL=C to get the traditional sort order that uses native byte values.
更新:看起来像是在包含Unicode字符时重现了这个问题。这个问题可以追溯到sort --试着对示例中的向量进行排序。我似乎也不能将语言环境(LC_COLLATE或LC_CTYPE)更改为"en_AU.UTF-8",这可能是一个潜在的解决方案。
发布于 2016-09-06 10:28:27
“factor”结构需要转换为字符值,因此需要以某种字体或其他字体进行编码。默认值是特定于操作系统的。词法排序顺序遵循locale。
在很大程度上,@Roland之前对这个问题的回答解决了地区问题,但没有解决编码问题:Is the default ("automatic") ordering for factors a part of the R specification? Alphabetical? Same on all platforms?
发布于 2016-09-06 13:39:04
我已尝试更改区域设置,但无法解决此问题。但是,鉴于我们可以将此问题追溯到sort函数,一种可能的替代方案是重新定义factor和as.factor函数,而不使用sort函数。
as.factor2 <- function(x){
if (is.factor(x))
x
else if (!is.object(x) && is.integer(x)) {
levels <- unique.default(x) # Removed sort()
f <- match(x, levels)
levels(f) <- as.character(levels)
class(f) <- "factor"
f
}
else factor2(x)
}
factor2 <- function (x = character(), levels, labels = levels, exclude = NA,
ordered = is.ordered(x), nmax = NA)
{
if (is.null(x))
x <- character()
nx <- names(x)
if (missing(levels)) {
y <- unique(x, nmax = nmax)
ind <- 1:length(y) # Changed from sort.list(y)
y <- as.character(y)
levels <- unique(y[ind])
}
force(ordered)
exclude <- as.vector(exclude, typeof(x))
x <- as.character(x)
levels <- levels[is.na(match(levels, exclude))]
f <- match(x, levels)
if (!is.null(nx))
names(f) <- nx
nl <- length(labels)
nL <- length(levels)
if (!any(nl == c(1L, nL)))
stop(gettextf("invalid 'labels'; length %d should be 1 or %d",
nl, nL), domain = NA)
levels(f) <- if (nl == nL)
as.character(labels)
else paste0(labels, seq_along(levels))
class(f) <- c(if (ordered) "ordered", "factor")
f
}我们现在可以按如下方式调用as.factor2:
as.factor2(c("\U201C",'"3', "1", "2","\U00B5"))
# [1] “ "3 1 2 µ
# Levels: "3 “ 1 2 µ我不会说这是您的问题的解决方案;它更像是一种变通方法。特别是因为这涉及到教学生,我不喜欢重新创建基R函数。希望其他人能提供一个更简单的解决方案。
https://stackoverflow.com/questions/39339489
复制相似问题