【问题标题】:How can I get a consistent return type from this function?如何从此函数获得一致的返回类型?
【发布时间】:2020-07-25 12:24:43
【问题描述】:

有没有办法让下面的函数返回一致的类型?我正在和Julia GLM 做一些工作(喜欢它)。我编写了一个函数,为数据集创建所有可能的回归组合。但是,我当前创建@formula 的方法为rhs 的每个不同长度返回不同的类型。

using GLM

function compose(lhs::Symbol, rhs::AbstractVector{Symbol})
    ts = term.((1, rhs...))
    term(lhs) ~ sum(ts)
end

使用@code_warntype 作为一个简单的示例会返回以下内容

julia> @code_warntype compose(:y, [:x])
Variables
  #self#::Core.Compiler.Const(compose, false)
  lhs::Symbol
  rhs::Array{Symbol,1}
  ts::Any

Body::FormulaTerm{Term,_A} where _A
1 ─ %1 = Core.tuple(1)::Core.Compiler.Const((1,), false)
│   %2 = Core._apply(Core.tuple, %1, rhs)::Core.Compiler.PartialStruct(Tuple{Int64,Vararg{Symbol,N} where N}, Any[Core.Compiler.Const(1, false), Vararg{Symbol,N} where N])
│   %3 = Base.broadcasted(Main.term, %2)::Base.Broadcast.Broadcasted{Base.Broadcast.Style{Tuple},Nothing,typeof(term),_A} where _A<:Tuple
│        (ts = Base.materialize(%3))
│   %5 = Main.term(lhs)::Term
│   %6 = Main.sum(ts)::Any
│   %7 = (%5 ~ %6)::FormulaTerm{Term,_A} where _A
└──      return %7

并检查几个不同输入的返回类型:

julia> compose(:y, [:x]) |> typeof
FormulaTerm{Term,Tuple{ConstantTerm{Int64},Term}}

julia> compose(:y, [:x1, :x2]) |> typeof
FormulaTerm{Term,Tuple{ConstantTerm{Int64},Term,Term}}

我们看到,随着rhs 长度的变化,返回类型也发生了变化。

我可以更改我的compose 函数以使其始终返回相同的类型吗?这真的不是什么大问题。为每个新数量的回归器编译只需要大约 70 毫秒。这实际上更像是“我如何提高我的 Julia 技能?”

【问题讨论】:

    标签: statistics julia regression glm


    【解决方案1】:

    我认为你不能在这里避免类型不稳定,因为 ~ 期望 RHS 是 TermTupleTerms。

    但是,您支付的最大编译成本是 term.((1, rhs...)),因为您调用了编译成本很高的广播。以下是您可以以更便宜的方式做到这一点的方法:

    function compose(lhs::Symbol, rhs::AbstractVector{Symbol})
        term(lhs) ~ ntuple(i -> i <= length(rhs) ? term(rhs[i]) : term(1) , length(rhs)+1)
    end
    

    或(这有点慢,但更像你的原始代码):

    function compose(lhs::Symbol, rhs::AbstractVector{Symbol})
        term(lhs) ~ map(term, (1, rhs...))
    end
    

    最后 - 如果你正在做这样的计算,也许你可以放弃使用公式接口,但直接作为 RHS 提供给 lmglm 矩阵,在这种情况下它应该能够避免额外的编译成本,例如:

    julia> y = rand(10);
    
    julia> x = rand(10, 2);
    
    julia> @time lm(x,y);
      0.000048 seconds (18 allocations: 1.688 KiB)
    
    julia> x = rand(10, 3);
    
    julia> @time lm(x,y);
      0.000038 seconds (18 allocations: 2.016 KiB)
    
    julia> y = rand(100);
    
    julia> x = rand(100, 50);
    
    julia> @time lm(x,y);
      0.000263 seconds (22 allocations: 121.172 KiB)
    

    【讨论】:

      猜你喜欢
      • 2021-06-16
      • 1970-01-01
      • 2023-02-22
      • 1970-01-01
      • 2020-04-29
      • 1970-01-01
      • 1970-01-01
      • 2016-05-18
      • 1970-01-01
      相关资源
      最近更新 更多