Есть ли лучшая альтернатива, чем манипуляции со строками для программного построения формул?

Кажется, что все остальные функции берут объекты формул, а затем делают с ними темную магию где-то глубоко внутри, и я ревную.

Я пишу функцию, которая подходит для нескольких моделей. Части формул для этих моделей остаются неизменными, и части переходят от одной модели к другой. Неуклюжий способ состоит в том, чтобы пользователь вводил части формулы в виде символьных строк, выполнял некоторые манипуляции с ними, а затем использовал as.formula,

Но прежде чем идти по этому пути, я просто хочу убедиться, что я не упускаю из виду какой-то более чистый способ сделать это, который позволил бы функции принимать формулы в стандартном формате R (например, извлеченный из других объектов, использующих формулы).

Я хочу что-то вроде...

> LHS <- y~1; RHS <- ~a+b; c(LHS,RHS);
y ~ a + b
> RHS2 <- ~c;
> c(LHS, RHS, RHS2);
y ~ a + b + c

или же...

> LHS + RHS;
y ~ a + b
> LHS + RHS + RHS2;
y ~ a + b + c

... но, к сожалению, ни один из синтаксисов не работает. Кто-нибудь знает, есть ли что-то, что делает? Благодарю.

1 ответ

Решение

reformulate будет делать то, что вы хотите.

reformulate(termlabels = c('x','z'), response = 'y')
## y ~ x + z

Или без перехвата

reformulate(termlabels = c('x','z'), response = 'y', intercept = FALSE)
## y ~ x + z - 1

Обратите внимание, что вы не можете создавать формулы с несколькими reponses такие как x+y ~z+b

reformulate(termlabels = c('x','y'), response = c('z','b'))
z ~ x + y

Извлечь условия из существующего formula (учитывая ваш пример)

attr(terms(RHS), 'term.labels')
## [1] "a" "b"

Чтобы получить ответ немного отличается, простой подход (для ответа одной переменной).

as.character(LHS)[2]
## [1] 'y'


combine_formula <- function(LHS, RHS){
  .terms <- lapply(RHS, terms)
  new_terms <- unique(unlist(lapply(.terms, attr, which = 'term.labels')))
  response <- as.character(LHS)[2]

  reformulate(new_terms, response)


}


combine_formula(LHS, list(RHS, RHS2))

## y ~ a + b + c
## <environment: 0x577fb908>

Я думаю, что было бы более разумно указать ответ как символьный вектор, что-то вроде

combine_formula2 <- function(response, RHS, intercept = TRUE){
  .terms <- lapply(RHS, terms)
  new_terms <- unique(unlist(lapply(.terms, attr, which = 'term.labels')))
  response <- as.character(LHS)[2]

  reformulate(new_terms, response, intercept)


}
combine_formula2('y', list(RHS, RHS2))

Вы также можете определить + оператор для работы с формулами (обновлена ​​установка нового метода для объектов формул)

`+.formula` <- function(e1,e2){
  .terms <- lapply(c(e1,e2), terms)
  reformulate(unique(unlist(lapply(.terms, attr, which = 'term.labels'))))
}

RHS + RHS2
## ~a + b + c

Вы также можете использовать update.formula с помощью . рассудительно

 update(~a+b, y ~ .)
 ##  y~a+b
Другие вопросы по тегам