[R] Creating model formulas programmatically
Duncan Murdoch
murdoch@dunc@n @end|ng |rom gm@||@com
Sun Mar 30 20:42:51 CEST 2025
On 2025-03-30 11:41 a.m., Bert Gunter wrote:
> Gabor, Duncan, et. al.
>
> 1. Thank you for your great comments and solutions. This is what I was
> hoping for!
>
> 2. Duncan: I completely agree with your criticisms. In fact, I realized the
> for() loop only needed the <- assignment, but your comment is important to
> note. However, I didn't like the for() loop either; I *much* preferred your
> Reduce() solution which is exactly the sort of elegant functionally based
> solution that R excels at. I am glad that you put it into the record.
>
> 3. If I may indulge those who are following this thread, yet another simple
> approach that just uses call() recursively is:
>
> recurseCall <- function(nms, FUN = '+')
> {
> if(length(nms) > 2) call(FUN, nms[[1]], Recall(nms[-1]))
> else call(FUN, nms[[1]],nms[[2]])
> }
> ## yielding
>> recurseCall(nms)
> Heigh + (Ho + (Silver + Away))
>
> While this result is different than that given by the others, it is
> syntactically equivalent and yields identical results when used.
> However, Duncan's Reduce() solution seems to me "obviously" better. In
> fact, I think recurseCall just recapitulates the logic of Reduce().
You can avoid the parens with
recurseCall2 <- function(nms, FUN = '+')
{ n <- length(nms)
if(n > 2) call(FUN, Recall(nms[-n]), nms[[n]])
else call(FUN, nms[[1]],nms[[2]])
}
By the way, your original recurseCall produces a slightly unusual
object. For some weird historical reasons, parens in R expressions are
parsed as function calls, they don't just affect order of operations.
So if you do
e <- quote(Heigh + (Ho + (Silver + Away)))
as.list(e[[3]])
you'll see this display:
[[1]]
`(`
[[2]]
Ho + (Silver + Away)
However, with the output of your function you'll see
e <- recurseCall(nms)
as.list(e[[3]])
[[1]]
`+`
[[2]]
Ho
[[3]]
Silver + Away
because in your object the parens were added during deparsing, they
aren't stored as part of the object.
Duncan Murdoch
>
> 4. And, again, I realize that versions of str2lang(paste(somename, collapse
> = ' + ')) work just fine, but I was explicitly interested in eliciting the
> bushel basket of elegant (imo) approaches that have been offered.
>
> Again, my thanks to all.
>
> Bert
>
>
>
>
>
>
>
>
> "An educated person is one who can entertain new ideas, entertain others,
> and entertain herself."
>
>
>
> On Sun, Mar 30, 2025 at 6:11 AM Gabor Grothendieck <ggrothendieck using gmail.com>
> wrote:
>
>> Another solution. reformulate + substitute + as.formula:
>>
>> substitute(~ (.)^2, list(. = reformulate(somenames)[[2]])) |> as.formula()
>>
>> On Sat, Mar 29, 2025 at 5:31 PM Bert Gunter <bgunter.4567 using gmail.com>
>> wrote:
>>>
>>> Note: I am almost certain that this has been asked and answered here
>>> before, so my apologies for the redundant query.
>>>
>>> I also know that there are several packages that will do this, but I wish
>>> to do it using base R functions only (see below).
>>>
>>> The query: Suppose I have a character vector of names like this:
>>> somenames <- c("Heigh", "Ho", "Silver", "Away")
>>> (maybe dozens or hundreds: i.e. lots of names)
>>>
>>> Now suppose want to put these in a model formula like this:
>>> ~ (Heigh + Ho + Silver + Away)^2
>>>
>>> ... But **without** pasting them into a character vector and using
>>> parse(text = ...) , which, I grant, is sometimes the simplest way.
>>> Instead, I want to do it using Base R's computing on the language
>>> functions. I can do this with bquote() or substitute(), for example, like
>>> this:
>>>
>>> somenames <- c("Heigh", "Ho", "Silver", "Away")
>>> nms <- lapply(somenames, as.name)
>>> form <- nms[[1]]
>>> for(x in nms[-1])
>>> form <<- bquote(.(form) + .(x), list(form = form, x = x))
>>> ## or form <<- substitute(form + x, list(form = form, x = x))
>>> form <- bquote(~ (.(form))^2, list(form =form))
>>>
>>> ## yielding
>>>> form
>>> ~(Heigh + Ho + Silver + Away)^2
>>>
>>> My question: Is there a simpler/slicker way to do this? This seems kinda
>>> kludgy, and I have the feeling that I'm missing something obviously
>> better
>>> (in base R only; obviously better stuff is in various packages)
>>>
>>> Best to all,
>>> Bert
>>>
>>> "An educated person is one who can entertain new ideas, entertain others,
>>> and entertain herself."
>>>
>>> [[alternative HTML version deleted]]
>>>
>>> ______________________________________________
>>> R-help using r-project.org mailing list -- To UNSUBSCRIBE and more, see
>>> https://stat.ethz.ch/mailman/listinfo/r-help
>>> PLEASE do read the posting guide
>> https://www.R-project.org/posting-guide.html
>>> and provide commented, minimal, self-contained, reproducible code.
>>
>>
>>
>> --
>> Statistics & Software Consulting
>> GKX Group, GKX Associates Inc.
>> tel: 1-877-GKX-GROUP
>> email: ggrothendieck at gmail.com
>>
>
> [[alternative HTML version deleted]]
>
> ______________________________________________
> R-help using r-project.org mailing list -- To UNSUBSCRIBE and more, see
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide https://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
More information about the R-help
mailing list