tipos - variacion explicada definicion
¿Cómo obtener confiablemente el nombre de la variable dependiente del objeto fórmula? (6)
Basándonos en su edición para obtener la respuesta real, no solo su nombre, podemos usar el lenguaje de evaluación no estándar empleado por lm()
y la mayoría de las otras funciones de modelado con una interfaz de fórmula en la base R
form <- formula("depVar ~ Var1 + Var2")
dat <- data.frame(depVar = rnorm(10), Var1 = rnorm(10), Var2 = rnorm(10))
getResponse <- function(form, data) {
mf <- match.call(expand.dots = FALSE)
m <- match(c("formula", "data"), names(mf), 0L)
mf <- mf[c(1L, m)]
mf$drop.unused.levels <- TRUE
mf[[1L]] <- as.name("model.frame")
mf <- eval(mf, parent.frame())
y <- model.response(mf, "numeric")
y
}
> getResponse(form, dat)
1 2 3 4 5
-0.02828573 -0.41157817 2.45489291 1.39035938 -0.31267835
6 7 8 9 10
-0.39945771 -0.09141438 0.81826105 0.37448482 -0.55732976
Como puede ver, esto obtiene los datos de la variable de respuesta real del marco de datos suministrado.
Cómo funciona esto es que la función primero captura la llamada de función sin expandir el argumento ...
ya que contiene cosas que no son necesarias para la evaluación de los datos de la fórmula.
A continuación, los argumentos "formula"
y "data"
coinciden con la llamada. La línea mf[c(1L, m)]
selecciona el nombre de la función de la llamada ( 1L
) y las ubicaciones de los dos argumentos coincidentes. El argumento drop.unused.levels
de model.frame()
se establece en TRUE
en la siguiente línea, y luego la llamada se actualiza para cambiar el nombre de la función en la llamada de lm
a model.frame
. Todo lo que hace el código anterior es tomar la llamada a lm()
y procesa esa llamada en una llamada a la función model.frame()
.
Esta llamada modificada se evalúa en el entorno principal de la función, que en este caso es el entorno global.
La última línea usa la función extractora model.response()
para tomar la variable de respuesta del marco del modelo.
Digamos que tengo la siguiente fórmula:
myformula<-formula("depVar ~ Var1 + Var2")
¿Cómo obtener de forma confiable el nombre de la variable dependiente del objeto de fórmula?
No pude encontrar ninguna función incorporada que sirva para este propósito. Sé que as.character(myformula)[[2]]
funciona, como lo hace
sub("^(//w*)//s~//s.*$","//1",deparse(myform))
Me parece que estos métodos son más una hacker, que un método confiable y estándar para hacerlo.
¿Alguien sabe tal vez exactamente qué método utiliza el lm
? He visto su código, pero es un poco críptico para mí ... aquí hay una cita para su conveniencia:
> lm
function (formula, data, subset, weights, na.action, method = "qr",
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE,
contrasts = NULL, offset, ...)
{
ret.x <- x
ret.y <- y
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]] <- as.name("model.frame")
mf <- eval(mf, parent.frame())
if (method == "model.frame")
return(mf)
else if (method != "qr")
warning(gettextf("method = ''%s'' is not supported. Using ''qr''",
method), domain = NA)
mt <- attr(mf, "terms")
y <- model.response(mf, "numeric")
w <- as.vector(model.weights(mf))
if (!is.null(w) && !is.numeric(w))
stop("''weights'' must be a numeric vector")
offset <- as.vector(model.offset(mf))
if (!is.null(offset)) {
if (length(offset) != NROW(y))
stop(gettextf("number of offsets is %d, should equal %d (number of observations)",
length(offset), NROW(y)), domain = NA)
}
if (is.empty.model(mt)) {
x <- NULL
z <- list(coefficients = if (is.matrix(y)) matrix(, 0,
3) else numeric(), residuals = y, fitted.values = 0 *
y, weights = w, rank = 0L, df.residual = if (!is.null(w)) sum(w !=
0) else if (is.matrix(y)) nrow(y) else length(y))
if (!is.null(offset)) {
z$fitted.values <- offset
z$residuals <- y - offset
}
}
else {
x <- model.matrix(mt, mf, contrasts)
z <- if (is.null(w))
lm.fit(x, y, offset = offset, singular.ok = singular.ok,
...)
else lm.wfit(x, y, w, offset = offset, singular.ok = singular.ok,
...)
}
class(z) <- c(if (is.matrix(y)) "mlm", "lm")
z$na.action <- attr(mf, "na.action")
z$offset <- offset
z$contrasts <- attr(x, "contrasts")
z$xlevels <- .getXlevels(mt, mf)
z$call <- cl
z$terms <- mt
if (model)
z$model <- mf
if (ret.x)
z$x <- x
if (ret.y)
z$y <- y
if (!qr)
z$qr <- NULL
z
}
Encontré un paquete útil ''formula.tools'' que es adecuado para su tarea.
Ejemplo de código:
f <- as.formula (a1 + a2 ~ a3 + a4)
lhs.vars (f) #tiene variables dependientes
[1] "a1" "a2"
rhs.vars (f) #tiene variables independientes
[1] "a3" "a4"
Esto siempre debería darte todos los vars dependientes:
myformula<-formula("depVar1 + depVar2 ~ Var1 + Var2")
as.character(myformula[[2]])[-1]
#[1] "depVar1" "depVar2"
Y no lo consideraría particularmente "hacky".
Editar:
Algo extraño sucede con 3 dependientes:
myformula<-formula("depVar1 + depVar2 + depVar3 ~ Var1 + Var2")
as.character(myformula[[2]])
#[1] "+" "depVar1 + depVar2" "depVar3"
Así que esto podría no ser tan confiable como pensaba.
Edit2:
De acuerdo, myformula[[2]]
es un objeto de lenguaje y as.character
parece hacer algo similar a languageEl
.
length(myformula[[2]])
#[1] 3
languageEl(myformula[[2]],which=1)
#`+`
languageEl(myformula[[2]],which=2)
#depVar1 + depVar2
languageEl(myformula[[2]],which=3)
#depVar3
languageEl(languageEl(myformula[[2]],which=2),which=2)
#depVar1
Si comprueba la longitud de cada elemento, puede crear su propia función de extracción. Pero esto es probablemente demasiado de un hack.
Edit3: Basado en la respuesta de @seancarmody all.vars(myformula[[2]])
es el camino a seguir.
Intenta usar all.vars
:
all.vars(myformula)[1]
Sé que esta pregunta es bastante antigua, pero pensé que agregaría una respuesta R base que no requiere indexación, no depende del orden de las variables enumeradas en una llamada a all.vars
y que da la respuesta variables como elementos separados cuando hay más de uno:
myformula <- formula("depVar1 + depVar2 ~ Var1 + Var2")
all_vars <- all.vars(myformula)
response <- all_vars[!(all_vars %in% labels(terms(myformula)))]
> response
[1] "depVar1" "depVar2"
Supongo que también podría cocinar su propia función para trabajar con terms()
:
getResponse <- function(formula) {
tt <- terms(formula)
vars <- as.character(attr(tt, "variables"))[-1] ## [1] is the list call
response <- attr(tt, "response") # index of response var
vars[response]
}
R> myformula <- formula("depVar ~ Var1 + Var2")
R> getResponse(myformula)
[1] "depVar"
Es tan hacky como un as.character(myformyula)[[2]]
pero tiene la seguridad de que obtiene la variable correcta, ya que el orden del árbol de análisis de llamadas no cambiará en el corto plazo.
Esto no es tan bueno con múltiples variables dependientes:
R> myformula <- formula("depVar1 + depVar2 ~ Var1 + Var2")
R> getResponse(myformula)
[1] "depVar1 + depVar2"
ya que necesitarán un procesamiento adicional.