In R, qual è esattamente il problema di avere variabili con lo stesso nome delle funzioni di base R?

Sembra essere generalmente considerata una ctriggers pratica di programmazione utilizzare nomi di variabili che hanno funzioni nella base R con lo stesso nome.

Ad esempio, si è tentati di scrivere:

data <- data.frame(...) df <- data.frame(...) 

Ora, i data della funzione caricano i set di dati mentre la funzione df calcola la funzione di densità f.

Allo stesso modo, si è tentati di scrivere:

 a <- 1 b <- 2 c <- 3 

Questo è considerato una ctriggers forma perché la funzione c combinerà i suoi argomenti.

Ma: in quel cavallo di battaglia delle funzioni R, lm , per calcolare modelli lineari, i data vengono usati come argomento. In altre parole, i data diventano una variabile esplicita all’interno della funzione lm .

Quindi: se il team R centrale può usare nomi identici per variabili e funzioni, cosa ci impedisce di essere dei semplici mortali?

La risposta non è che R si confonderà. Prova il seguente esempio, in cui assegno esplicitamente una variabile con il nome c . R non si confonde affatto con la differenza tra variabile e funzione:

 c("A", "B") [1] "A" "B" c <- c("Some text", "Second", "Third") c(1, 3, 5) [1] 1 3 5 c[3] [1] "Third" 

La domanda: qual è esattamente il problema di avere una variabile con lo stesso nome della funzione di base R?

Non ce n’è veramente uno. Normalmente, R non cerca oggetti (oggetti non funzionali) quando cerca una funzione:

 > mean(1:10) [1] 5.5 > mean <- 1 > mean(1:10) [1] 5.5 > rm(mean) > mean(1:10) [1] 5.5 

Gli esempi mostrati da @Joris e @Sacha sono quelli in cui la ctriggers codifica ti cattura. Un modo migliore per scrivere foo è:

 foo <- function(x, fun) { fun <- match.fun(fun) fun(x) } 

Che quando usato dà:

 > foo(1:10, mean) [1] 5.5 > mean <- 1 > foo(1:10, mean) [1] 5.5 

Ci sono situazioni in cui questo ti sorprenderà e l'esempio di @ Joris con na.omit è uno, quale IIRC, sta accadendo a causa della valutazione standard, non standard, usata in lm() .

Diverse risposte hanno anche confuso il problema T vs TRUE con il problema del mascheramento delle funzioni. Poiché T e TRUE non sono funzioni che sono un po 'al di fuori della portata della domanda di @ Andrie.

Il problema non è tanto il computer, ma l’utente. In generale, il codice può diventare molto più difficile eseguire il debug. Gli errori di battitura sono fatti molto facilmente, quindi se lo fai:

 c <- c("Some text", "Second", "Third") c[3] c(3) 

Ottieni i risultati corretti. Ma se manchi da qualche parte in un codice e digiti c(3) invece di c[3] , trovare l'errore non sarà così facile.

L'analisi può anche portare a rapporti di errore molto confusi. Prendi la seguente funzione imperfetta:

 my.foo <- function(x){ if(x) c <- 1 c + 1 } > my.foo(TRUE) [1] 2 > my.foo(FALSE) Error in c + 1 : non-numeric argument to binary operator 

Con funzioni più complesse, questo può portarti su un percorso di debug che non porta da nessuna parte. Se si sostituisce c con x nella funzione precedente, l'errore leggerà " object 'x' not found ". Ciò condurrà molto più velocemente al tuo errore di codifica.

Accanto a ciò, può portare a un codice piuttosto confuso. Il codice come c(c+c(a,b,c)) richiede più dal cervello che c(d+c(a,b,d)) . Ancora una volta, questo è un esempio banale, ma può fare la differenza.

E ovviamente, puoi anche ottenere degli errori. Quando ti aspetti una funzione, non la otterrai, il che può dar luogo a un altro set di fastidiosi bug:

 my.foo <- function(x,fun) fun(x) my.foo(1,sum) [1] 1 my.foo(1,c) Error in my.foo(1, c) : could not find function "fun" 

Un esempio più realistico (e reale) di come ciò possa causare problemi:

 x <- c(1:10,NA) y <- c(NA,1:10) lm(x~y,na.action=na.omit) # ... correct output ... na.omit <- TRUE lm(x~y,na.action=na.omit) Error in model.frame.default(formula = x ~ y, na.action = na.omit, drop.unused.levels = TRUE) : attempt to apply non-function 

Prova a capire cosa c'è che non va qui se na.omit <- TRUE verifica 50 righe nel tuo codice ...

Rispondi a modifica dopo commento di @Andrie per includere l'esempio di segnalazioni di errori confusi

R è molto robusto per questo, ma puoi pensare a modi per romperlo. Ad esempio, considera questa funzione:

 foo <- function(x,fun) fun(x) 

Che si applica semplicemente a x . Non è il modo più carino per farlo, ma potresti incontrare questo da qualcuno script o qualcosa del genere. Questo funziona per mean() :

 > foo(1:10,mean) [1] 5.5 

Ma se assegno un nuovo valore significa che si rompe:

 mean <- 1 foo(1:10,mean) Error in foo(1:10, mean) : could not find function "fun" 

Questo accadrà molto raramente, ma potrebbe accadere. È anche molto confuso per le persone se la stessa cosa significa due cose:

 mean(mean) 

Poiché è banale utilizzare qualsiasi altro nome che si desidera, perché non utilizzare un nome diverso, quindi basare le funzioni R? Inoltre, per alcune variabili R questo diventa ancora più importante. Pensa a riassegnare la funzione '+' ! Un altro buon esempio è la riassegnazione di T e F che può interrompere così tanti script.

Penso che il problema sia quando le persone usano queste funzioni nell’ambiente globale e possono causare frustrazione a causa di alcuni errori imprevisti che non dovresti ottenere. Immagina di aver appena eseguito un esempio riproducibile (forse piuttosto lungo) che ha sovrascritto una delle funzioni che stai utilizzando nella tua simulazione che impiega anni per arrivare dove vuoi e poi improvvisamente si rompe con un errore divertente. L’uso di nomi di funzioni già esistenti per variabili in un ambiente chiuso (come una funzione) viene rimosso dopo la chiusura della funzione e non deve causare danni. Supponendo che il programmatore sia consapevole di tutte le conseguenze di tale comportamento.

La risposta è semplice Bene, tipo di

La linea di fondo è che si dovrebbe evitare la confusione. Tecnicamente non vi è alcun motivo per fornire i nomi propri alle variabili, ma facilita la lettura del codice.

Immagina di avere una riga di codice contenente qualcosa come data()[1] o simile (questa linea probabilmente non ha senso, ma è solo un esempio): anche se ora ti è chiaro che stai usando i dati della funzione qui, un lettore che ha notato che ci sono dati con nome data.frame, potrebbe essere confuso.

E se non sei altruisticamente incline, ricorda che il lettore potrebbe essere te tra un anno e mezzo, cercando di capire cosa stavi facendo con “quel vecchio codice”.

Prendilo da un uomo che ha imparato a usare nomi variabili lunghi e convenzioni di denominazione: ripaga!

Sono d’accordo con @Gavin Simpson e @Nick Sabbe che non c’è davvero un problema, ma questa è più una questione di leggibilità del codice. Quindi, come molte cose nella vita, è una questione di convenzione e consenso.

E penso che sia una buona convenzione dare il consiglio generale: non nominare le variabili come le funzioni di base R!

Questo consiglio funziona come altri buoni consigli. Ad esempio, sappiamo tutti che non beviamo troppo alcol e non mangiamo cibo troppo malsano, ma di tanto in tanto non possiamo seguire questi consigli e ubriacarci mentre mangiamo troppo cibo spazzatura.

Lo stesso vale per questo consiglio. Ovviamente ha senso nominare i dati degli argomenti dei data . Ma ha molto meno senso nominare una mean vettoriale di dati. Anche se ci possono essere situazioni in cui anche questo sembra appropriato. Ma cerca di evitare quelle situazioni per chiarezza.

Mentre alcune lingue potrebbero consentirlo, IF IF THEN THEN ELSE ELSE vieni in mente. In generale è considerata una pratica molto povera. Non è che non vogliamo darti l’opportunità di mostrare la tua conoscenza avanzata della lingua, è che un giorno, dovremo occuparci di quel codice e siamo solo dei mortali.

Quindi salva i tuoi trucchi di programmazione rompendo le build notturne e dai alle tue variabili nomi ragionevoli, con involucro consistente se ti senti particolarmente caldo e sfocato.