Подтвердить что ты не робот

Разница между именами (df [1]) <- `и` names (df) [1] <- `

Рассмотрим следующее:

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
4b9b3361

Ответ 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