apply() 函数在对每一列调用函数之前将其第一个参数强制转换为矩阵。因此,您的数据框被强制转换为矩阵对象。该转换的结果是 as.matrix(df_AB) 具有非空行名,而 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 在他的 cmets 中指出的那样,您可以使用 .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.