Извлекать переменные в формуле из кадра данных
У меня есть формула, содержащая некоторые термины и кадр данных (вывод более раннего вызова model.frame()
), который содержит все эти термины и еще несколько. Я хочу, чтобы подмножество рамки модели содержало только переменные, которые фигурируют в формуле.
ff <- log(Reaction) ~ log(1+Days) + x + y
fr <- data.frame(`log(Reaction)`=1:4,
`log(1+Days)`=1:4,
x=1:4,
y=1:4,
z=1:4,
check.names=FALSE)
Желаемый результат fr
минус столбец z
(fr[,1:4]
изменяет - мне нужно программное решение...)
Некоторые стратегии, которые не работают:
fr[all.vars(ff)]
## Error in `[.data.frame`(fr, all.vars(ff)) : undefined columns selected
(потому что all.vars()
получает "Reaction"
, а не log("Reaction")
)
stripwhite <- function(x) gsub("(^ +| +$)","",x)
vars <- stripwhite(unlist(strsplit(as.character(ff)[-1],"\\+")))
fr[vars]
## Error in `[.data.frame`(fr, vars) : undefined columns selected
(поскольку расщепление на +
ложно разбивает член log(1+Days)
).
Я думал о том, чтобы спуститься по дереву разбора формулы:
ff[[3]] ## log(1 + Days) + x + y
ff[[3]][[1]] ## `+`
ff[[3]][[2]] ## log(1 + Days) + x
но у меня нет решения, и кажется, что я иду по кроличьей дыре. Идеи?
Ответы
Ответ 1
Это должно работать:
> fr[gsub(" ","",rownames(attr(terms.formula(ff), "factors")))]
log(Reaction) log(1+Days) x y
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
И реквизит Романа Луштрика для указания меня в правильном направлении.
Edit: Похоже, вы могли бы отключить его и от атрибута "variables":
fr[gsub(" ","",attr(terms(ff),"variables")[-1])]
Изменить 2: найти первый проблемный случай с участием I()
или offset()
:
ff <- I(log(Reaction)) ~ I(log(1+Days)) + x + y
fr[gsub(" ","",attr(terms(ff),"variables")[-1])]
Тем не менее, это можно было бы легко исправить с помощью регулярного выражения. НО, если бы у вас были ситуации, подобные в вопросе, где вызывается переменная, например, log(x)
и используется в формуле рядом с чем-то вроде I(log(y))
для переменной y
, это будет действительно беспорядочно.
Ответ 2
Мне кажется, что единственная проблема заключается в отсутствии пробела во имя второго столбца fr. Переименуйте его в пространстве и вытащите столбцы следующим образом:
ff <- log(Reaction) ~ log(1+Days) + x + y
fr <- data.frame(`log(Reaction)`=1:4,
`log(1 + Days)`=1:4,
x=1:4,
y=1:4,
z=1:4,
check.names=FALSE)
fr[labels(terms(ff))]
Если вы считаете, что единственная разница между ними всегда будет заключаться в том, что имена fr
имеют пробелы, где имена в ff
не совпадают, то указанное выше решение выполняется. Мне нравится labels(terms(x))
немного больше, хотя, потому что это кажется немного более абстрактным.
fr[gsub(pattern = ' ', replacement = '', x = labels(terms(ff)))]