请考虑以下事项:
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
答案 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
有效,因为我们直接分配值而不是属性,所以这里没有问题。
`[.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