2014-05-02 19 views
21

Si consideri il seguente:Differenza tra `nomi (df [1]) <-` e `nomi (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 

Entrambi i metodi non ha prodotto un errore, ma il prima non ha cambiato il nome della colonna, mentre il secondo ha fatto.

ho pensato che ha qualcosa a che fare con il fatto che sto operando solo su un sottoinsieme di df, ma perché, per esempio, il seguente funziona bene allora?

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

Mi piace la risposta di Joshua qui: http://stackoverflow.com/a/10449502/1270695. Dice che è magico. – A5C1D2H2I1M1N2O1R2T1

+0

La risposta di Giosuè si riferisce al secondo esempio, non a quello che non ha fatto nulla ... –

+2

Ohboyohboy, sei qui per un regalo: leggi questa (in) famosa monografia - http: //www.burns-stat .com/pages/Tutor/R_inferno.pdf –

risposta

26

Quello che penso sta accadendo è che la sostituzione in una cornice di dati ignora gli attributi del frame di dati che è tratto da. Io non sono sicuro al 100% di questo, ma i seguenti esperimenti apparire una copia di backup:

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 

che produce:

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

notare come i valori modificati per df, ma non i nomi. Fondamentalmente l'operatore sostitutivo `[<-` sostituisce solo i valori. Questo è il motivo per cui il nome non è stato aggiornato. Credo che questo spieghi tutti i problemi.

Nello scenario:

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

si può pensare l'assegnazione come segue (questa è una semplificazione, vedi fine del post per maggiori dettagli):

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 

L'ultimo passo di cui è un compito con `[<-`, che non rispetta l'attributo dei nomi del RHS.

Ma nello scenario:

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

si può pensare l'assegnazione come (ancora una volta, una semplificazione):

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 

Notate come abbiamo direttamente assegniamo a names, invece di assegnare a df che ignora gli attributi.

df[2] <- 2 

opere perché stiamo assegnando direttamente ai valori, non i attributi, quindi non ci sono problemi qui.


EDIT: sulla base di alcuni commenti da @ AriB.Friedman, qui è una versione più elaborata di quello che penso sta succedendo (nota sto omettendo l'invio S3 per `[.data.frame`, etc., Per chiarezza):

Versione 1 names(df[2]) <- "x" traduce:

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

versione 2 names(df)[2] <- "x" traduce:

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

Inoltre, risulta questa è "documentato" in R Inferno Sezione 8.2.34 (Grazie @ Frog):

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