我有以下函数,我想用Optim.jl最小化多个参数:
function post(parm,y,x,n)
# Evaluate the log of the marginal posterior for parm at a point
fgamma=zeros(n,1);
for ii = 1:2
fgamma = fgamma + parm[ii+1]*(x[:,ii+1].^parm[4]);
end
fgamma = fgamma.^(1/parm[4]);
fgamma = fgamma + parm[1]*ones(n,1);
lpost = .5*n*log.((y - fgamma)'*(y-fgamma));
end
但是,当我尝试使用optimize
时,Julia会返回错误。
旧错误(使用parm):
MethodError: no method matching finite_difference!(::##1#2, ::Array{Float64,2}, ::Array{Float64,2}, ::Symbol)
新错误(使用parm2):
MethodError: Cannot `convert` an object of type Array{Float64,2} to an object of type Float64
我正在使用的包含数据和优化调用的完整脚本是:
using Distributions
using Optim
n = 200;
k = 3;
x = ones(n,k);
fgamma=zeros(n,1);
gam = [1.01; 0.6; 0.8; 1.5];
x[:,2] = rand(Chisq(10),n);
x[:,3] = rand(Chisq(5),n);
epsl = rand(Normal(0,1),n);
y = zeros(n,1);
for i = 1:n
y[i,1] = gam[1] + (gam[2]*x[i,2]^gam[4] + gam[3]*x[i,3]^gam[4])^(1/gam[4]) + epsl[i];
end
# Sim
bols = inv(x'x)x'y;
s2 = (y-x*bols)'*(y-x*bols)/(n-k);
sse=(n-k)*s2;
bolscov = s2.*inv(x'*x);
bolssd=zeros(k,1);
for i = 1:k
bolssd[i,1]=sqrt(bolscov[i,i]);
end
# Calculate posterior mode and Hessian at mode
nparam=k+1;
parm = ones(nparam,1);
parm[1:k,1]=bols;
parm2 = vec(parm);
opt = Optim.Options(f_tol = 1e-8, iterations = 1000);
Optim.after_while!{T}(d, state::Optim.BFGSState{T}, method::BFGS, options) = global invH = state.invH
res = optimize(p -> post(p,y,x,n), parm2, BFGS(), opt)
有谁知道我做错了什么?我认为函数lpost
中post
的类型存在问题,因为它返回1x1数组{Float64,2}。不幸的是,我无法很好地处理它。
答案 0 :(得分:0)
错误消息
MethodError: Cannot `convert` an object of type Array{Float64,2} to an object of type Float64
是由尝试将矩阵转换为标量引起的。一般情况下这是不可能的,但是当矩阵是1x1矩阵时(正如问题所指出的那样),存在一个自然变换:scalar = matrix[1,1]
。
optimize
需要返回标量值,因为它是标量非线性优化例程。优化矢量值甚至难以明确定义(Pareto optima等概念试图这样做)。
因此,在这个前奏之后,修复很简单,同时解决了复杂优化@fst(海报)的问题。同样,需要单维标量,因此real(...)
用于从复数值(更准确地说是有序标量)中生成标量,因为复数也是标量。生成的post
函数为:
function post(parm,y,x,n)
# Evaluate the log of the marginal posterior for parm at a point
fgamma=zeros(n,1);
for ii = 1:2
fgamma = fgamma + parm[ii+1]*(x[:,ii+1].^parm[4]);
end
fgamma = fgamma.^Complex(1/parm[4]);
fgamma = fgamma + parm[1]*ones(n,1);
lpost = .5*n*log.((y - fgamma)'*(y-fgamma));
return real(lpost[1,1])
end