`names(df [1])< - `和`names(df)[1] < - `之间的区别

Dav*_*urg 23 r dataframe

考虑以下:

df <- data.frame(a = 1, b = 2, c = 3)
names(df[1]) <- "d" ## First method
##  a b c
##1 1 2 3

names(df)[1] <- "d" ## Second method
##  d b c
##1 1 2 3
Run Code Online (Sandbox Code Playgroud)

这两种方法都没有返回错误,但第一次没有更改列名,而第二次没有.

我认为它与我只在一个子集上运行的事实有关df,但为什么,例如,以下工作正常呢?

df[1] <- 2 
##  a b c
##1 2 2 3
Run Code Online (Sandbox Code Playgroud)

Bro*_*ieG 27

我认为发生的事情是替换到数据框会忽略从中抽取的数据框的属性.我不是100%肯定这一点,但以下实验似乎支持它:

df <- data.frame(a = 1:3, b = 5:7)
#   a b
# 1 1 5
# 2 2 6
# 3 3 7

df2 <- data.frame(c = 10:12)
#    c
# 1 10
# 2 11
# 3 12

df[1] <- df2[1]   # in this case `df[1] <- df2` is equivalent
Run Code Online (Sandbox Code Playgroud)

哪个产生:

#    a b
# 1 10 5
# 2 11 6
# 3 12 7
Run Code Online (Sandbox Code Playgroud)

注意值是如何更改的df,而不是名称.基本上,替换运算符`[<-`仅替换值.这就是名称未更新的原因.我相信这解释了所有问题.

在场景中:

names(df[2]) <- "x"
Run Code Online (Sandbox Code Playgroud)

您可以将分配视为如下(这是一个简化,有关更多详细信息,请参见文章末尾):

tmp <- df[2]
#   b
# 1 5
# 2 6
# 3 7

names(tmp) <- "x"
#   x
# 1 5
# 2 6
# 3 7

df[2] <- tmp   # `tmp` has "x" for names, but it is ignored!
#    a b
# 1 10 5
# 2 11 6
# 3 12 7
Run Code Online (Sandbox Code Playgroud)

最后一步是赋值`[<-`,它不尊重RHS的名称属性.

但在场景中:

names(df)[2] <- "x"
Run Code Online (Sandbox Code Playgroud)

您可以将赋值视为(再次,简化):

tmp <- names(df)
# [1] "a" "b"

tmp[2] <- "x"
# [1] "a" "x"

names(df) <- tmp
#    a x
# 1 10 5
# 2 11 6
# 3 12 7
Run Code Online (Sandbox Code Playgroud)

注意我们如何直接分配names,而不是分配df哪些忽略属性.

df[2] <- 2
Run Code Online (Sandbox Code Playgroud)

因为我们直接分配给值而不是属性,所以这里没有问题.


编辑:根据@ AriB.Friedman的一些评论,这里是我认为正在进行的更详细的版本(注意我省略了S3发送`[.data.frame`等,为了清楚起见):

版本1 names(df[2]) <- "x"转换为:

df <- `[<-`(
  df, 2, 
  value=`names<-`(   # `names<-` here returns a re-named one column data frame
    `[`(df, 2),       
    value="x"
) ) 
Run Code Online (Sandbox Code Playgroud)

版本2 names(df)[2] <- "x"转换为:

df <- `names<-`(
  df,
  `[<-`(
     names(df), 2, "x"
) )
Run Code Online (Sandbox Code Playgroud)

另外,事实证明这是在R Inferno Section 8.2.34中记录的"(感谢@Frank):

right <- wrong <- c(a=1, b=2)
names(wrong[1]) <- 'changed'
wrong
# a b
# 1 2
names(right)[1] <- 'changed'
right
# changed b
# 1 2
Run Code Online (Sandbox Code Playgroud)