为什么对该数据框进行子集化会更改其(以前重复的)列名?

Why does subsetting this data frame change its (formerly duplicated) column names?

考虑

DF <- data.frame(
  x=1:5,
  y=5:1,
  z=rep(5,5),
  danger=11:15,
  danger=12:16,
  check.names = FALSE
)
drops <- c("x","z")
DF
DF[!(names(DF) %in% drops)]

有了这个,我们得到以下输出:

> DF
  x y z danger danger
1 1 5 5     11     12
2 2 4 5     12     13
3 3 3 5     13     14
4 4 2 5     14     15
5 5 1 5     15     16

> DF[!(names(DF) %in% drops)]
  y danger danger.1
1 5     11       12
2 4     12       13
3 3     13       14
4 2     14       15
5 1     15       16

如我们所见,最后一列的名称已更改。为什么?

代码中发生了几件事。 OP 在构造 data.frame 时用 check.names = FALSE 覆盖了对列名的默认检查,这允许重复的列名,因为如果它是 TRUE,那么触发的事件链将是以下函数被调用

 make.names -> make.unique

make.unique 默认附加一个 . 和一个数字作为重复元素的后缀

make.unique(rep("danger", 2))
#[1] "danger"   "danger.1"

duplicate 不推荐在 data.frame 中使用列名。因此,当我们使用 [ 执行子集时,会调用 data.frame 的 Extract 方法

methods(`[`)

return 一堆方法,其中一个是 [.data.frame,它检查名称并使用从 make.unique[=33 获得的唯一名称分配给 names =]

`[.data.frame`
...
...
if (has.j && anyDuplicated(nm <- names(x))) 
        names(x) <- make.unique(nm)
...

对于 [,传递的参数只有 ijdrop 以及对象 'x'

formalArgs(`[.data.frame`)
#[1] "x"    "i"    "j"    "drop"

因此,我们不能通过在此处传递任何 check.names 来覆盖该行为


但是,matrix 没有重复列名的问题

as.matrix(DF)[, !(names(DF) %in% drops)]
#      y danger danger
#[1,] 5     11     12
#[2,] 4     12     13
#[3,] 3     13     14
#[4,] 2     14     15
#[5,] 1     15     16

注意:建议不要在 matrixdata.frame 中使用重复的列名,因为这可能会在代码中产生不必要的错误