2016-09-06 28 views
7

为什么这个代码:as.factor(c("\U201C", '"3', "1", "2", "\U00B5")),在每个操作系统上返回不同的因子水平排序?为什么unicode字符串上的as.factor()会为每个操作系统返回不同的结果?

在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 µ

我有一些学生提交的R包含as.numeric(as.factor(dat$var))的Mardkown作业。现在认为这不是一种好的代码编写方式,但是输出的不一致导致了很多混乱和浪费时间。

+0

虽然很奇怪,但在FreeBSD和OS X上是一样的。不知道差异来自哪里,但知道OS X和FreeBSD之间的相似之处可能会有所帮助? – Jemus42

+2

我没有答案,但它实际上可能来自R中的'sort'函数。查看'as.factor'的代码,您有'levels < - sort(unique.default(x))''。我已经在Windows和Mac OS上尝试过'排序'并获得不同的排序。 – jav

+3

这是一个区域设置,特别是'LC_COLLATE'。你可以用'Sys.setlocale'来设置它,看看发生了什么。 – alistaire

回答

4

这不仅仅是Unicode而且不仅仅是R;一般而言(如甚至在* nix命令sort中)可以是区域特定的。需要在所有机器上设置LC_COLLATE(推测为"C")通过Sys.setlocale(根据@ alistaire的评论)来消除差异。

对于我来说,在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" 

在两台机器上完全相同。

* nix中mansort给出了大胆的警告

*** 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_COLLATELC_CTYPE)更改为"en_AU.UTF-8",这将是一个潜在的解决方案。

+0

感谢乔诺!我在Windows和Linux上将LC_COLLATE设置为“C”,并且顺序更接近一些,但仍然不相同。 – MilesMcBain

+0

你能否更新MRE以显示还没有匹配的东西?可能是一种代表性的东西。 –

+0

已更新。 Unicode不能很好地发挥作用,它可以通过改变为'UTF-8'来解决,但我无法弄清楚如何强制它这么做。 –

0

我试图改变区域设置,但我无法来解决这个问题。但是,考虑到我们可以将此问题追溯到sort函数,可能的替代方法是重新定义factoras.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函数。希望别人可以提供更简单的解决方案。

+0

这可能会产生意想不到的后果。有些功能可能会假设层次是有序的。 – Roland

+0

这会始终按照遇到的顺序返回因子?这似乎是最好的平台不可知的方式来做到这一点。我同意重写基地并不好,但它总是发生。例如。 'read_csv()'和'read.csv()'。顺便提一句,这个问题可能由'read.csv()'继承。也许我们可以让Hadley把'as_factor()'放到'Forcats'中。 – MilesMcBain

+0

我不是这个答案的粉丝,因为它意味着你可能会失去字母排序顺序,这比Unicode字符串更常见。 –

相关问题