有人可以解释一下为什么我在下面的最后两行代码(identical()
调用)中会得到不同的结果吗?
这两个对象似乎是相同的对象,但是当我在apply函数中使用它们时,我遇到了一些麻烦:
df <- data.frame(a = 1:5, b = 6:2, c = rep(7,5))
df_ab <- df[,c(1,2)]
df_AB <- subset(df, select = c(1,2))
identical(df_ab,df_AB)
[1] TRUE
apply(df_ab,2,function(x) identical(1:5,x))
a b
TRUE FALSE
apply(df_AB,2,function(x) identical(1:5,x))
a b
FALSE FALSE
答案 0 :(得分:13)
apply()
函数在调用每列上的函数之前强制将其第一个参数强制转换为矩阵。因此,您的数据框被强制转换为矩阵对象。转换的结果是as.matrix(df_AB)
具有非空的rownames,而as.matrix(df_ab)
则没有:
> str(as.matrix(df_ab))
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:2] "a" "b"
> str(as.matrix(df_AB))
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2
- attr(*, "dimnames")=List of 2
..$ : chr [1:5] "1" "2" "3" "4" ...
..$ : chr [1:2] "a" "b"
因此当apply()
对df_AB
列进行子集时,会得到一个命名向量,它与未命名的向量不同。
apply(df_AB, 2, str)
Named int [1:5] 1 2 3 4 5
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ...
Named int [1:5] 6 5 4 3 2
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ...
NULL
与subset()
函数进行对比,后者使用逻辑向量为i
的值选择行。看起来像对i
的非缺失值的data.frame进行子集化会导致row.names
属性出现这种差异:
> str(as.matrix(df[1:5, 1:2]))
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2
- attr(*, "dimnames")=List of 2
..$ : chr [1:5] "1" "2" "3" "4" ...
..$ : chr [1:2] "a" "b"
> str(as.matrix(df[, 1:2]))
int [1:5, 1:2] 1 2 3 4 5 6 5 4 3 2
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:2] "a" "b"
您可以使用.Internal(inspect(x))
函数查看data.frames之间差异的所有细节。如果你有兴趣,你可以自己看一下。
正如Roland在评论中指出的那样,您可以使用.row_names_info()
函数来查看行名称的差异。
请注意,如果缺少i
,则.row_names_info()
的结果为否定,但如果您使用非遗漏i
进行分组,则结果为正。
> .row_names_info(df_ab, type=1)
[1] -5
> .row_names_info(df_AB, type=1)
[1] 5
这些值的含义在?.row_names_info
中解释:
type: integer. Currently ‘type = 0’ returns the internal ‘"row.names"’ attribute (possibly ‘NULL’), ‘type = 2’ the number of rows implied by the attribute, and ‘type = 1’ the latter with a negative sign for ‘automatic’ row names.
答案 1 :(得分:8)
如果要将值1:5
与列中的值进行比较,则不应使用apply
,因为apply
会在应用函数之前将数据帧转换为矩阵。由于使用[
创建的子集中的行名称(请参阅@Joshua Ulrich的答案),值1:5
与包含相同值的命名向量不同。
您应该使用sapply
将identical
函数应用于列。这避免了将数据帧转换为矩阵:
> sapply(df_ab, identical, 1:5)
a b
TRUE FALSE
> sapply(df_AB, identical, 1:5)
a b
TRUE FALSE
如您所见,在两个数据框架中,第一列中的值与1:5
相同。
答案 2 :(得分:5)
在一个版本中(使用[
),您的列是整数,而在另一个版本中(使用subset
),您的列被命名为整数。
apply(df_ab, 2, str)
int [1:5] 1 2 3 4 5
int [1:5] 6 5 4 3 2
NULL
apply(df_AB, 2, str)
Named int [1:5] 1 2 3 4 5
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ...
Named int [1:5] 6 5 4 3 2
- attr(*, "names")= chr [1:5] "1" "2" "3" "4" ...
NULL
答案 3 :(得分:3)
在之前查看这两个对象的结构,它们被提交到apply
只显示了一个区别:在rownames中,但没有我预期产生的差异你看到的差异。我没有看到约书亚目前提供的&#39;子集&#39;作为解释这个的逻辑索引。为什么row.names = c(NA, -5L))
在使用&#34; [&#34;尚未解释。
> dput(df_AB)
structure(list(a = 1:5, b = c(6L, 5L, 4L, 3L, 2L)), .Names = c("a",
"b"), row.names = c(NA, 5L), class = "data.frame")
> dput(df_ab)
structure(list(a = 1:5, b = c(6L, 5L, 4L, 3L, 2L)), .Names = c("a",
"b"), class = "data.frame", row.names = c(NA, -5L))
我同意这是as.matrix强制,需要进一步调查:
> attributes(df_AB[,1])
NULL
> attributes(df_ab[,1])
NULL
> attributes(as.matrix(df_AB)[,1])
$names
[1] "1" "2" "3" "4" "5"