R 转置相同的对象

R 转置相同的对象,r,matrix,transpose,R,Matrix,Transpose,我今天得到一个奇怪的结果 复制它,考虑下面的数据帧: x <- data.frame(x=1:3, y=11:13) y <- x[1:3, 1:2] 将t() identical(t(x),t(y)) # [1] FALSE 不同之处在于列名: colnames(t(x)) # NULL colnames(t(y)) # [1] "1" "2" "3" 有鉴于此,如果您想按列堆叠y,您将得到预期的结果: stack(as.data.frame(t(y))) # valu

我今天得到一个奇怪的结果

复制它,考虑下面的数据帧:

x <- data.frame(x=1:3, y=11:13)
y <- x[1:3, 1:2] 
t()

identical(t(x),t(y))
# [1] FALSE
不同之处在于列名:

colnames(t(x))
# NULL
colnames(t(y))
# [1] "1" "2" "3"
有鉴于此,如果您想按列堆叠
y
,您将得到预期的结果:

stack(as.data.frame(t(y)))
#   values ind
# 1      1   1
# 2     11   1
# 3      2   2
# 4     12   2
# 5      3   3
# 6     13   3
而:

stack(as.data.frame(t(x)))
#     values ind
# 1      1  V1
# 2     11  V1
# 3      2  V2
# 4     12  V2
# 5      3  V3
# 6     13  V3
在后一种情况下,
as.data.frame()
找不到原始列名并自动生成它们

罪魁祸首位于
as.matrix()
,被称为
t()

解决方法是设置
行名。强制

rownames(as.matrix(x, rownames.force=TRUE))
# [1] "1" "2" "3"
rownames(as.matrix(y, rownames.force=TRUE))
# [1] "1" "2" "3"
identical(t(as.matrix(x, rownames.force=TRUE)), 
          t(as.matrix(y, rownames.force=TRUE)))
# [1] TRUE
(并相应地重写
堆栈(…)
调用。)

我的问题是:

  • 为什么
    as.matrix()
    会区别对待
    x
    y

  • 你如何区分它们之间的区别

  • 请注意,其他信息功能不会显示x和y之间的差异:

    identical(attributes(x), attributes(y))
    # [1] TRUE
    identical(str(x), str(y))
    # ...
    #[1] TRUE
    
    对解决办法的评论 对上述行为给出简洁而有效的解释(另请参见 有关更多详细信息)

    简言之,康拉德表明:

    a)
    x
    y
    内部不同
    b) “
    相同”
    在默认情况下过于宽松”无法捕捉这种内部差异

    现在,如果你取集
    S
    的子集
    T
    ,其中包含
    S
    的所有元素,那么
    S
    T
    是完全相同的对象。因此,如果您使用一个数据帧
    y
    ,它包含
    x
    的所有行和列,那么
    x
    y
    应该是完全相同的对象。不幸的是
    x\neq y

    这种行为不仅违反直觉,而且混淆不清,也就是说,区别不是不言而喻的,只是内部的,甚至默认的
    相同的
    函数都看不到它

    另一个自然原理是,将两个相同的(类似矩阵的)对象转置会生成相同的对象。同样,在转置之前,
    idential
    是“过于宽松”的事实打破了这一点;转置后,默认的
    相同的
    就足以看到差异

    对于像R这样的科学语言来说,这种行为(即使不是bug)是一种不当行为
    希望这个帖子会引起一些注意,R团队会考虑修改它。

    作为注释,<代码> x<代码>和<代码> y>代码>不完全相同。当我们调用

    t
    data.frame
    ,将执行
    t.data.frame

    function (x) 
    {
        x <- as.matrix(x)
        NextMethod("t")
    }
    
    正如@oropendola所评论的,
    x
    y
    .row\u names\u info
    的返回是不同的,上面的函数就是差异生效的地方

    那么为什么
    y
    行名不同呢?让我们看看
    [.data.frame
    ,我在关键行添加了注释:

    {
        ... # many lines of code
        xx <- x  #!! this is where xx is defined
        cols <- names(xx)
        x <- vector("list", length(x))
        x <- .Internal(copyDFattr(xx, x))  # This is where I am not sure about
        oldClass(x) <- attr(x, "row.names") <- NULL
        if (has.j) {
            nm <- names(x)
            if (is.null(nm)) 
                nm <- character()
            if (!is.character(j) && anyNA(nm)) 
                names(nm) <- names(x) <- seq_along(x)
            x <- x[j]
            cols <- names(x)
            if (drop && length(x) == 1L) {
                if (is.character(i)) {
                    rows <- attr(xx, "row.names")
                    i <- pmatch(i, rows, duplicates.ok = TRUE)
                }
                xj <- .subset2(.subset(xx, j), 1L)
                return(if (length(dim(xj)) != 2L) xj[i] else xj[i, 
                                                                , drop = FALSE])
            }
            if (anyNA(cols)) 
                stop("undefined columns selected")
            if (!is.null(names(nm))) 
                cols <- names(x) <- nm[cols]
            nxx <- structure(seq_along(xx), names = names(xx))
            sxx <- match(nxx[j], seq_along(xx))
        }
        else sxx <- seq_along(x)
        rows <- NULL ## this is where rows is defined, as we give numeric i, the following
        ## if block will not be executed
        if (is.character(i)) {
            rows <- attr(xx, "row.names")
            i <- pmatch(i, rows, duplicates.ok = TRUE)
        }
        for (j in seq_along(x)) {
            xj <- xx[[sxx[j]]]
            x[[j]] <- if (length(dim(xj)) != 2L) 
                xj[i]
            else xj[i, , drop = FALSE]
        }
        if (drop) {
            n <- length(x)
            if (n == 1L) 
                return(x[[1L]])
            if (n > 1L) {
                xj <- x[[1L]]
                nrow <- if (length(dim(xj)) == 2L) 
                    dim(xj)[1L]
                else length(xj)
                drop <- !mdrop && nrow == 1L
            }
            else drop <- FALSE
        }
        if (!drop) { ## drop is False for our case
            if (is.null(rows)) 
                rows <- attr(xx, "row.names")  ## rows changed from NULL to 1,2,3 here
            rows <- rows[i]
            if ((ina <- anyNA(rows)) | (dup <- anyDuplicated(rows))) {
                if (!dup && is.character(rows)) 
                    dup <- "NA" %in% rows
                if (ina) 
                    rows[is.na(rows)] <- "NA"
                if (dup) 
                    rows <- make.unique(as.character(rows))
            }
            if (has.j && anyDuplicated(nm <- names(x))) 
                names(x) <- make.unique(nm)
            if (is.null(rows)) 
                rows <- attr(xx, "row.names")[i]
            attr(x, "row.names") <- rows  ## this is where the rownames of x changed
            oldClass(x) <- oldClass(xx)
        }
        x
    }
    
    因此,当我们使用
    [.data.frame
    创建
    y
    时,它会接收与
    x
    不同的
    行.names
    属性,其中
    行.names
    是自动的,并在
    dput
    结果中用负号表示


    编辑 事实上,这已在以下手册中说明:

    row.names类似于数组的rownames,它有一个 调用数组参数的行名

    对于n>2,格式为1:n的行名称存储在一个压缩文件中 表单,可以从C代码中看到,也可以通过去粗化看到,但不能通过 row.names或attr(x,“row.names”)。此外,此 排序标记为“自动”,并由as.matrix进行不同的处理 和data.matrix(以及可能的其他函数)


    因此,
    attr
    不区分自动
    行名称(如
    x
    )和显式整数
    行名称(如
    y
    ),而这是通过
    作为区分的。矩阵
    通过内部表示法
    。行_名称_信息

    相同
    默认情况下过于宽松,但您可以更改:

    > identical(x, y, attrib.as.set = FALSE)
    [1] FALSE
    
    通过更详细地检查对象,可以找到原因:

    > dput(x)
    structure(list(x = 1:3, y = 11:13), .Names = c("x", "y"), row.names = c(NA,
    -3L), class = "data.frame")
    > dput(y)
    structure(list(x = 1:3, y = 11:13), .Names = c("x", "y"), row.names = c(NA,
    3L), class = "data.frame")
    
    请注意不同的
    行。名称
    属性:

    > .row_names_info(x)
    [1] -3
    > .row_names_info(y)
    [1] 3
    

    从文档中我们可以看出,负数意味着自动行名(对于
    x
    ),而
    y
    的行名不是自动的。
    as.matrix
    对它们的处理方式不同。

    似乎是
    行名的定义方式,因为它们在
    dput(x)
    dput中是不同的(y
    )。可能它们是在使用
    [.data.frame
    时显式添加的。您可以使用dput(x)和dput(y),您将看到row.names以不同的方式存储。我认为这与自动row.names处理有关(有关更多信息,请查看详细信息部分),不知道为什么子集返回不同的row.names,但是…老实说,它闻起来像是一个意外的行为,
    idential(x,y,attrib.as.set=FALSE)
    似乎发现了差异(注意
    ?idential
    “注意idential(x,y,FALSE,FALSE,FALSE,FALSE)严格地测试完全相等。”as.matrix在调用
    .row\u names\u info
    时与@digEmAll指出的不同之处在于
    x
    中的自动行名。正如所写,
    as.matrix
    删除了自动行名,这样它们就不会在矩阵中作为行名结束。值得注意的是
    attr(x,“row.names”)
    attr(x,“row.names”)=value
    不显示R在内部如何处理“row.names”的特定情况。
    .row\u names\u info
    更准确。例如
    attr(x,“row.names”)=1:3
    不将
    1:3
    存储为“row.names”,但如
    .row\u names\u info(x,0)所示
    。但是,除了
    NULL
    之外的任何符号都会将对象标记为
    > attr(x, 'row.names')
    [1] 1 2 3
    
    > identical(x, y, attrib.as.set = FALSE)
    [1] FALSE
    
    > dput(x)
    structure(list(x = 1:3, y = 11:13), .Names = c("x", "y"), row.names = c(NA,
    -3L), class = "data.frame")
    > dput(y)
    structure(list(x = 1:3, y = 11:13), .Names = c("x", "y"), row.names = c(NA,
    3L), class = "data.frame")
    
    > .row_names_info(x)
    [1] -3
    > .row_names_info(y)
    [1] 3