Questa risposta coprirà molti degli stessi elementi delle risposte esistenti, ma questo problema (passare i nomi delle colonne alle funzioni) si presenta abbastanza spesso che volevo che ci fosse una risposta che coprisse le cose in modo un po 'più completo.
Supponiamo di avere un data frame molto semplice:
dat <- data.frame(x = 1:4,
y = 5:8)
e vorremmo scrivere una funzione che crea una nuova colonna z
che è la somma delle colonne x
e y
.
Un ostacolo molto comune qui è che un tentativo naturale (ma errato) spesso assomiglia a questo:
foo <- function(df,col_name,col1,col2){
df$col_name <- df$col1 + df$col2
df
}
#Call foo() like this:
foo(dat,z,x,y)
Il problema qui è che df$col1
non valuta l'espressione col1
. Cerca semplicemente una colonna in df
letteralmente chiamata col1
. Questo comportamento è descritto nella ?Extract
sezione "Oggetti ricorsivi (simili a liste)".
La soluzione più semplice e più spesso consigliata è semplicemente passare da $
a [[
e passare gli argomenti della funzione come stringhe:
new_column1 <- function(df,col_name,col1,col2){
#Create new column col_name as sum of col1 and col2
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column1(dat,"z","x","y")
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
Questa è spesso considerata "best practice" poiché è il metodo più difficile da sbagliare. Passare i nomi delle colonne come stringhe è quanto di più inequivocabile è possibile ottenere.
Le due opzioni seguenti sono più avanzate. Molti pacchetti popolari fanno uso di questo tipo di tecniche, ma usarle bene richiede maggiore attenzione e abilità, poiché possono introdurre sottili complessità e punti di fallimento imprevisti. Questa sezione del libro Advanced R di Hadley è un eccellente riferimento per alcuni di questi problemi.
Se vuoi davvero salvare l'utente dalla digitazione di tutte quelle virgolette, un'opzione potrebbe essere quella di convertire i nomi di colonna spogli e non quotati in stringhe usando deparse(substitute())
:
new_column2 <- function(df,col_name,col1,col2){
col_name <- deparse(substitute(col_name))
col1 <- deparse(substitute(col1))
col2 <- deparse(substitute(col2))
df[[col_name]] <- df[[col1]] + df[[col2]]
df
}
> new_column2(dat,z,x,y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
Questo è, francamente, un po 'sciocco probabilmente, dal momento che stiamo davvero facendo la stessa cosa di in new_column1
, solo con un po' di lavoro extra per convertire i nomi nudi in stringhe.
Infine, se vogliamo essere davvero fantasiosi, potremmo decidere che invece di passare i nomi di due colonne da aggiungere, vorremmo essere più flessibili e consentire altre combinazioni di due variabili. In tal caso, probabilmente ricorreremo all'uso di eval()
un'espressione che coinvolge le due colonne:
new_column3 <- function(df,col_name,expr){
col_name <- deparse(substitute(col_name))
df[[col_name]] <- eval(substitute(expr),df,parent.frame())
df
}
Tanto per divertimento, sto ancora usando deparse(substitute())
per il nome della nuova colonna. Qui funzioneranno tutti i seguenti elementi:
> new_column3(dat,z,x+y)
x y z
1 1 5 6
2 2 6 8
3 3 7 10
4 4 8 12
> new_column3(dat,z,x-y)
x y z
1 1 5 -4
2 2 6 -4
3 3 7 -4
4 4 8 -4
> new_column3(dat,z,x*y)
x y z
1 1 5 5
2 2 6 12
3 3 7 21
4 4 8 32
Quindi la risposta breve è fondamentalmente: passare i nomi delle colonne data.frame come stringhe e utilizzare [[
per selezionare singole colonne. Solo iniziare approfondendo eval
, substitute
ecc se davvero sa cosa si sta facendo.