Suppose I have a formula like this: f <- y ~ qss(x, lambda = lambdas[1]) + qss(z, lambdas[2]) + s I?d like a function, g(lambdas, f) that would take g(c(2,3), f) and produce the new formula: y ~ qss(x, lambda = 2) + qss(z, 3) + s For only two qss terms I have been using g <- function(lambdas, f){ F <- deparse(f) F <- gsub("lambdas\\[1\\]",lambdas[1],F) F <- gsub("lambdas\\[2\\]",lambdas[2],F) formula(F) } but this is ugly and doesn?t extend nicely to more qss terms. Isn?t there some bquote() magic that can be invoked? Or something else entirely?
Recursively walk the formula performing the replacement: g <- function(e, ...) { if (length(e) > 1) { if (identical(e[[2]], as.name(names(list(...))))) { e <- eval(e, list(...)) } if (length(e) > 1) for (i in 1:length(e)) e[[i]] <- Recall(e[[i]], ...) } e } g(f, lambdas = 2:3) ## y ~ qss(x, lambda = 2L) + qss(z, 3L) + s On Fri, Oct 23, 2020 at 9:33 AM Koenker, Roger W <rkoenker at illinois.edu> wrote:> > Suppose I have a formula like this: > > f <- y ~ qss(x, lambda = lambdas[1]) + qss(z, lambdas[2]) + s > > I?d like a function, g(lambdas, f) that would take g(c(2,3), f) and produce the new > formula: > > y ~ qss(x, lambda = 2) + qss(z, 3) + s > > For only two qss terms I have been using > > g <- function(lambdas, f){ > F <- deparse(f) > F <- gsub("lambdas\\[1\\]",lambdas[1],F) > F <- gsub("lambdas\\[2\\]",lambdas[2],F) > formula(F) > } > but this is ugly and doesn?t extend nicely to more qss terms. Isn?t there some > bquote() magic that can be invoked? Or something else entirely? > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://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
Thanks, Gabor! Very elegant!> On Oct 23, 2020, at 4:15 PM, Gabor Grothendieck <ggrothendieck at gmail.com> wrote: > > Recursively walk the formula performing the replacement: > > g <- function(e, ...) { > if (length(e) > 1) { > if (identical(e[[2]], as.name(names(list(...))))) { > e <- eval(e, list(...)) > } > if (length(e) > 1) for (i in 1:length(e)) e[[i]] <- Recall(e[[i]], ...) > } > e > } > > g(f, lambdas = 2:3) > ## y ~ qss(x, lambda = 2L) + qss(z, 3L) + s > > On Fri, Oct 23, 2020 at 9:33 AM Koenker, Roger W <rkoenker at illinois.edu> wrote: >> >> Suppose I have a formula like this: >> >> f <- y ~ qss(x, lambda = lambdas[1]) + qss(z, lambdas[2]) + s >> >> I?d like a function, g(lambdas, f) that would take g(c(2,3), f) and produce the new >> formula: >> >> y ~ qss(x, lambda = 2) + qss(z, 3) + s >> >> For only two qss terms I have been using >> >> g <- function(lambdas, f){ >> F <- deparse(f) >> F <- gsub("lambdas\\[1\\]",lambdas[1],F) >> F <- gsub("lambdas\\[2\\]",lambdas[2],F) >> formula(F) >> } >> but this is ugly and doesn?t extend nicely to more qss terms. Isn?t there some >> bquote() magic that can be invoked? Or something else entirely? >> ______________________________________________ >> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see >> https://stat.ethz.ch/mailman/listinfo/r-help >> PLEASE do read the posting guide http://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
I can't compete with Gabor's "elegant" solution, but I don't understand why your original "ugly" approach doesn't work. g <- function(lambdas, f){ z <- as.character(f) for(i in seq_along(lambdas)) z[3]<- sub(paste0("lambdas[", i, "]"), lambdas[i], z[3], fixed TRUE) formula(paste0(z[c(2,1,3)], collapse = " ")) }> f <- y ~ qss(x, lambda = lambdas[1]) + qss(z, lambdas[2]) + s > g(1:2, f)y ~ qss(x, lambda = 1) + qss(z, 2) + s <environment: 0x7f930e768598>> f <- y ~ qss(x, lambda = lambdas[1]) + qss(z, lambdas[2]) ++ qss(z,lambdas[3]) + s> g(3:1, f)y ~ qss(x, lambda = 3) + qss(z, 2) + qss(z, 1) + s <environment: 0x7f930e7404f0> Is there maybe a problem with the environment of the created formula? Or have I misunderstood what you wanted? Cheers, Bert Bert Gunter "The trouble with having an open mind is that people keep coming along and sticking things into it." -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip ) On Fri, Oct 23, 2020 at 6:33 AM Koenker, Roger W <rkoenker at illinois.edu> wrote:> Suppose I have a formula like this: > > f <- y ~ qss(x, lambda = lambdas[1]) + qss(z, lambdas[2]) + s > > I?d like a function, g(lambdas, f) that would take g(c(2,3), f) and > produce the new > formula: > > y ~ qss(x, lambda = 2) + qss(z, 3) + s > > For only two qss terms I have been using > > g <- function(lambdas, f){ > F <- deparse(f) > F <- gsub("lambdas\\[1\\]",lambdas[1],F) > F <- gsub("lambdas\\[2\\]",lambdas[2],F) > formula(F) > } > but this is ugly and doesn?t extend nicely to more qss terms. Isn?t there > some > bquote() magic that can be invoked? Or something else entirely? > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide > http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code. >[[alternative HTML version deleted]]