Ответ 1
То, что я думаю, происходит, заключается в том, что замена в кадре данных игнорирует атрибуты создаваемого кадра данных. Я не уверен на 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
работает, потому что мы назначаем непосредственно значения, а не атрибуты, поэтому проблем здесь нет.
EDIT: на основе некоторого комментария от @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"
) )
Версия 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