Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

method for human to make formula with FunctionTerm #232

Closed
PharmCat opened this issue Aug 3, 2021 · 5 comments
Closed

method for human to make formula with FunctionTerm #232

PharmCat opened this issue Aug 3, 2021 · 5 comments

Comments

@PharmCat
Copy link

PharmCat commented Aug 3, 2021

Method for human to make formula with FunctionTerm in expression.

I try to make dynamic formula like this:

module XXX
using StatsModels
global i = Symbol()
for  v in [:a, :b]
    i = v
    model = eval(:(
    StatsModels.capture_call(log, (($i,)->log($i)),
    (i,),
    $(Expr(:copyast, :($(QuoteNode(:(log($i))))))),
    [StatsModels.Term(i)]
    )
    ~ Term(:AX)))
#some code with lm()
end
end

for simple Term it easy:

:(Term(:y) ~ ConstantTerm(1) + Term(:a) + Term(:b) + Term(:a) & Term(:b))

at the end i get:

ERROR: MethodError: no method matching (::Main.XXX.var"#7#8")(::Float64)
The applicable method may be too new: running in world age 30095, while current world is 30096.
@ndgnuh
Copy link

ndgnuh commented Aug 7, 2021

My current workaround:

function single_functional_term(f, x)
	symbol = Expr(:call, Symbol(f), x)
	fanon = eval(:(($x,) -> log($x)))
	StatsModels.capture_call(f, fanon, (x,), symbol, [Term(x)])
end

f = let res = Term(:y)
	pres = mapreduce(vcat, 1:3) do i
		s = Symbol("x$i")
		[Term(s), single_functional_term(log, s)]
	end
	FormulaTerm(res, (pres...,))
end

It doesn't work on multiple arity functions though, like (x, y) -> log(x*y)


My second hack by abusing the @formula macro:

function functional_term(f, arg_expr...)
	expr = Expr(:call, Symbol(f), arg_expr...)
	eval(:(@formula somethingsomethingvarhopefullynodup ~ $expr)).rhs
end

t1 = functional_term(log, :(x * y))
t2 = functional_term(*, :x, :y)
t3 = functional_term(*, [Symbol("x$i") for i in 1:4]...)
display(t1)
# (x,y)->log(x * y)
display(t2)
# x(unknown)
# y(unknown)
# x(unknown) & y(unknown)
display(t3)
# x1(unknown)
# x2(unknown)
# x3(unknown)
# x4(unknown)
# x1(unknown) & x2(unknown)
# x1(unknown) & x3(unknown)
# x2(unknown) & x3(unknown)
# x1(unknown) & x4(unknown)
# x2(unknown) & x4(unknown)
# x3(unknown) & x4(unknown)
# x1(unknown) & x2(unknown) & x3(unknown)
# x1(unknown) & x2(unknown) & x4(unknown)
# x1(unknown) & x3(unknown) & x4(unknown)
# x2(unknown) & x3(unknown) & x4(unknown)
# x1(unknown) & x2(unknown) & x3(unknown) & x4(unknown)

@kleinschmidt
Copy link
Member

See #183 ... with that proposal you can construct them a lot more easily since there's no need for an anonymous function.

For now I'd suggest using @ndgnuh solution, except you can do @eval(@formula(0 ~ $expr)).rhs (use 0 on the LHS)

@kleinschmidt
Copy link
Member

There's definitely no reason to deal with capture_call directly, that's just to make the macro itself a bit cleaner to write :) Once you're doing any kind of eval you might as well use @formula

@PharmCat
Copy link
Author

PharmCat commented Jan 1, 2023

seems second case not working with GLM

@kleinschmidt
Copy link
Member

#183 is merged and there are examples in the tests of how to create function terms programatically!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants