转置相同的对象

ant*_*nio 15 transpose r matrix

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

要复制它,请考虑以下数据框:

x <- data.frame(x=1:3, y=11:13)
y <- x[1:3, 1:2] 
Run Code Online (Sandbox Code Playgroud)

他们应该是,实际上是相同的:

identical(x,y)
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)

应用于 t()indentical对象应该产生相同的结果,但是:

identical(t(x),t(y))
# [1] FALSE
Run Code Online (Sandbox Code Playgroud)

不同之处在于列名:

colnames(t(x))
# NULL
colnames(t(y))
# [1] "1" "2" "3"
Run Code Online (Sandbox Code Playgroud)

鉴于此,如果您想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
Run Code Online (Sandbox Code Playgroud)

而:

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
Run Code Online (Sandbox Code Playgroud)

在后一种情况下, as.data.frame()找不到原始列名并自动生成它们.

罪魁祸首是as.matrix(),通过所谓t():

rownames(as.matrix(x))
# NULL
rownames(as.matrix(y))
# [1] "1" "2" "3"
Run Code Online (Sandbox Code Playgroud)

解决方法是设置rownames.force:

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
Run Code Online (Sandbox Code Playgroud)

(并相应地重写 stack(...)调用.)

我的问题是:

  1. 为什么as.matrix()对待不同xy

  2. 你怎么能分辨出它们之间的区别?

请注意,其他信息功能不会揭示以下差异x, y:

identical(attributes(x), attributes(y))
# [1] TRUE
identical(str(x), str(y))
# ...
#[1] TRUE
Run Code Online (Sandbox Code Playgroud)

评论解决方案

Konrad Rudolph对上述行为给出了简明但有效的解释( 更多细节见mt1022).

简而言之,康拉德表明:

一个)xy内部不同;
b)" identical默认情况下太简单了"以捕捉这种内部差异.

现在,如果你把一个子TS,里面有所有的元素S,然后ST 是完全一样的对象.所以,如果你把一个数据帧y,它具有所有的行和列x,那么xy 完全一样的对象.很遗憾x \neq y!
这种行为不仅违反直觉,而且也是混淆的,也就是说,差异不是不言自明的,而只是内部甚至默认identical功能都看不到它.

另一个自然原则是,转置两个相同的(矩阵状)对象会产生相同的对象.再一次,在转置之前,identical"太松懈" 的事实打破了这一点 ; 在转置后,默认 identical值足以看出差异.

恕我直言这种行为(即使它不是一个错误)是像R 这样的科学语言的不当行为.
希望这篇文章会引起一些注意,R团队会考虑修改它.

Kon*_*lph 5

identical 在默认情况下太简单了,但您可以更改:

> identical(x, y, attrib.as.set = FALSE)
[1] FALSE
Run Code Online (Sandbox Code Playgroud)

可以通过更详细地检查对象找到原因:

> 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")
Run Code Online (Sandbox Code Playgroud)

请注意不同的row.names属性:

> .row_names_info(x)
[1] -3
> .row_names_info(y)
[1] 3
Run Code Online (Sandbox Code Playgroud)

从文档中我们可以收集到负数意味着自动的rownames(for x),而y行的名称不是自动的.并as.matrix以不同的方式对待它们.

  • 没有分歧.`row.names`的帮助页面说"表格1的行名:n为n> n的内部以紧凑的形式存储,......"和"as.matrix"和"其他函数"将"处理[这种名称的方式不同." 运行跟踪('row.names')表明它为提问者的例子被调用了3次(至少有一次调用`print(y`)).它还说:"`row.names`将始终返回一个字符向量.(如果需要检索一组整数值的行名,请使用`attr(x,"row.names")." (2认同)