2015-09-09 15 views
14

Nel corpo di alcune funzioni R, ad esempio lm, vedo le chiamate alla funzione match.call. Come dice la pagina di aiuto, se utilizzato all'interno di una funzione, match.call restituisce una chiamata in cui vengono specificati i nomi degli argomenti; e questo dovrebbe essere utile per passare un gran numero di argomenti a un'altra funzione.Perché match.call è utile?

Per esempio, nella funzione lm vediamo una chiamata alla funzione model.frame

function (formula, data, subset, weights, na.action, method = "qr", 
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
contrasts = NULL, offset, ...) 
{ 
cl <- match.call() 
mf <- match.call(expand.dots = FALSE) 
m <- match(c("formula", "data", "subset", "weights", "na.action", 
    "offset"), names(mf), 0L) 
mf <- mf[c(1L, m)] 

mf$drop.unused.levels <- TRUE 
mf[[1L]] <- quote(stats::model.frame) 
mf <- eval(mf, parent.frame()) 

Perché questo è più utile di effettuare una chiamata direttamente al model.frame specificando i nomi degli argomenti, come devo fare?

function (formula, data, subset, weights, na.action, method = "qr", 
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
contrasts = NULL, offset, ...) 
{ 
mf <- model.frame(formula = formula, data = data, 
        subset = subset, weights = weights, subset = subset) 

Nota che match.call ha un altro uso che io non discuto, conservare la chiamata in oggetto risultante.

+6

Per uno, non hai scritto tutto questo. Puoi fare cose come passare tutti gli argomenti contemporaneamente, qualcosa come 'f <- function (x, y, z) do.call (" sum ", as.list (match.call() [- 1])); f (1, 2, 3) ## [1] 6'. Ovviamente questo sarebbe molto più utile per una lunga lista di argomenti nominati –

+0

Abbastanza giusti, immagino che si possa anche fare l'affettamento dell'argomento inverso. 'f <- function (x, y, z) {l <- as.list (match.call()) [- 1]; do.call (sum, l [setdiff (names (l), 'z') ])} '. Ad ogni modo, credo di essere stato confuso riguardo l'uso in 'lm'. Tuttavia trovo che tutto sia risolvibile con l'argomento '...' abbastanza facilmente. Credo di essere pignolo. – Usobi

+2

@Usobi: 'match.call()' è più robusto nel senso seguente? Se usi '...' allora non sai quali argomenti vengono passati e potresti finire con le cose passate che non vuoi o che rompono le cose in modi inaspettati. D'altra parte, se si ripetono esplicitamente i nomi degli argomenti per passarli, questo renderà il codice più difficile da refactificare se si cambiano le definizioni degli argomenti della funzione. – peterthinking

risposta

7

Un motivo rilevante qui è che match.call acquisisce la lingua della chiamata senza valutarla e in questo caso consente a lm di considerare alcune delle variabili "mancanti" come "facoltative". Si consideri:

lm(x ~ y, data.frame(x=1:10, y=runif(10))) 

Vs:

lm2 <- function (
    formula, data, subset, weights, na.action, method = "qr", 
    model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, 
    contrasts = NULL, offset, ... 
) { 
    mf <- model.frame(
    formula = formula, data = data, subset = subset, weights = weights 
) 
} 
lm2(x ~ y, data.frame(x=1:10, y=runif(10))) 
## Error in model.frame.default(formula = formula, data = data, subset = subset, : 
## invalid type (closure) for variable '(weights)' 

In lm2, dal momento che weights è "mancante", ma è ancora usarlo in weights=weights, R tenta di utilizzare la funzione di stats::weights che evidentemente non è ciò che si intendeva. È possibile aggirare questo problema testando la mancanza prima di chiamare lo model.frame, ma a quel punto lo match.call inizia a sembrare piuttosto buono. Un'occhiata a cosa succede se ci debug la chiamata:

debug(lm2) 
lm2(x ~ y, data.frame(x=1:10, y=runif(10))) 
## debugging in: lm2(x ~ y, data.frame(x = 1:10, y = runif(10))) 
## debug at #5: { 
##  mf <- model.frame(formula = formula, data = data, subset = subset, 
##   weights = weights) 
## } 
Browse[2]> match.call() 
## lm2(formula = x ~ y, data = data.frame(x = 1:10, y = runif(10))) 

match.call non coinvolge gli argomenti mancanti a tutti.

Si potrebbe sostenere che gli argomenti facoltativi avrebbero dovuto essere resi esplicitamente facoltativi tramite valori predefiniti, ma non è quello che è successo qui.