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

时间:2014-05-02 12:13:31

标签: 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

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

我认为这与我仅在df的子集上操作这一事实有关,但为什么,例如,以下工作正常呢?

df[1] <- 2 
##  a b c
##1 2 2 3

1 个答案:

答案 0 :(得分: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

产生:

#    a b
# 1 10 5
# 2 11 6
# 3 12 7

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

在场景中:

names(df[2]) <- "x"

您可以将分配视为如下(这是一个简化,请参阅帖子的结尾以获取更多详细信息):

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

最后一步是使用`[<-`的作业,它不尊重RHS的名称属性。

但在场景中:

names(df)[2] <- "x"

您可以将分配视为(再次,简化):

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

请注意我们如何直接分配到names,而不是分配给忽略属性的df

df[2] <- 2

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


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

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

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

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

df <- `names<-`(
  df,
  `[<-`(
     names(df), 2, "x"
) )

另外,事实证明这是“记录”在R Inferno第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