我今天得到了一个奇怪的结果。
要复制它,请考虑以下数据框:
x <- data.frame(x=1:3, y=11:13)
y <- x[1:3, 1:2]
它们应该是并且实际上是相同的:
identical(x,y)
# [1] TRUE
将t()
应用于indentical对象应该产生相同的结果,但是:
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))
# NULL
rownames(as.matrix(y))
# [1] "1" "2" "3"
解决方法是设置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
(并相应地重写stack(...)
。)
我的问题是:
为什么as.matrix()
区别对待x
和y
以及
你怎么能区分它们呢?
请注意,其他信息功能不会显示x, y
:
identical(attributes(x), attributes(y))
# [1] TRUE
identical(str(x), str(y))
# ...
#[1] TRUE
Konrad Rudolph为上述行为提供了简明但有效的解释(另请参阅mt1022 更多细节)。
简而言之,康拉德表明:
a)x
和y
内部不同;
b)“identical
在默认情况下过于宽松”是为了捕捉这种内部差异。
现在,如果您使用集合T
的子集S
,其中 all 的元素为S
,则S
和T
是完全相同的对象。因此,如果您采用数据框y
, all x
的行和列,则x
和y
应该完全相同的对象。不幸的是x \neq y
!
这种行为不仅违反直觉,而且也是混淆的,也就是说,差异不是明显的,只有内部,甚至默认的identical
函数都看不到它。
另一个自然原则是,转置两个相同的(矩阵状)对象会产生相同的对象。同样,在转置之前,identical
“太宽松”这一事实打破了这一点;在转置后,默认identical
足以看出差异。
恕我直言,这种行为(即使它不是一个错误)是对诸如R的科学语言的不良行为 希望这篇文章会引起一些关注,R团队会考虑修改它。
答案 0 :(得分:5)
identical
默认情况下过于宽松,但您可以更改:
> 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
属性:
> .row_names_info(x)
[1] -3
> .row_names_info(y)
[1] 3
从文档中我们可以看出负数表示自动rownames(对于x
),而y
的行名不是自动的。 as.matrix
对待他们的方式不同。
答案 1 :(得分:3)
在评论中,db:reset db:migrate
和x
并不完全相同。当我们致电y
至t
时,data.frame
将被执行:
t.data.frame
我们可以看到,它调用了function (x)
{
x <- as.matrix(x)
NextMethod("t")
}
,即as.matrix
:
as.matrix.data.frame
正如@oropendola评论的那样,function (x, rownames.force = NA, ...)
{
dm <- dim(x)
rn <- if (rownames.force %in% FALSE)
NULL
else if (rownames.force %in% TRUE)
row.names(x)
else if (.row_names_info(x) <= 0L)
NULL
else row.names(x)
...
和.row_names_info
的{{1}}的回报是不同的,上述函数是差异生效的地方。
那么为什么x
有不同的y
?让我们看看y
,我在关键行添加了评论:
rownames
我们可以看到[.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
}
:
y
因此,当我们使用attr(x, 'row.names')
创建> attr(x, 'row.names')
[1] 1 2 3
时,它会收到与y
不同的[.data.frame
个属性,其中row.names
是自动的并显示为x
结果中出现负号。
实际上,这已在row.names
手册中说明:
请注意
row.names类似于数组的rownames,它有一个方法 调用数组参数的rownames。
表单1的行名称:n表示n> 2内部存储在紧凑型中 表单,可以从C代码中看到,也可以从deparsing中看到,但从不通过 row.names或attr(x,“row.names”)。另外,有些名字 sort被标记为“自动”,并由as.matrix以不同方式处理 和data.matrix(以及可能的其他功能)。
所以row.names
不会区分自动dput
(如attr
)和显式整数row.names
(如x
的那个),而row.names
通过内部代表y
对此进行区分。