Julia中文文档:https://docs.juliacn.com/latest/stdlib/LinearAlgebra/#LinearAlgebra.eigmin
鼎鼎有名的泰勒展开式
收敛速度快
增加了一个步长,步长用划界法或其他方法来确定,保证每步都下降(修正目的)
为非线性回归的目标函数是使残差最小,本质上还是一个求最小值的问题
O矩阵的元素一般为0,可以省略
可见高斯牛顿法只需要用到一阶偏导即可
using LinearAlgebra
function GaosiNewton(
f, # 要拟合成的函数
g, # 梯度,是针对偏回归系数
data, # 数据,每一行代表的是一个点,前面是自变量,最后一列是响应变量
start; # 牛顿法的起始点
α0 = 1, # 步长
acc = 0.001,
maxI = 128,
debug = false,
plot = false # 是否输出迭代点
)
end
(放在主函数内)
function getR(para)
return mapslices(row ->f(row[1:end-1]...,para...)-row[end], data, dims = [2])
end
# 定义计算J函数
function getJ()
return mapslices(row->g(row[1:end-1]...,x0...), data, dims = [2])
end
x0 = start
I = Diagonal(ones(length(start)))
r0 = getR(x0)
s0 = sum(r0 .^ 2)
# 取得维度
n,m = size(data)
if m < length(start)
return false
end
for i in 1:maxI
J0 = getJ()
g0 = J0' * r0
h0 = J0' * J0
# 求出的em是最小的特征值
# 修正黑塞矩阵
em = eigmin(h0)
if em < 0
h0 = h0-1.1*em * I
end
# Newton
if det(h0) ==0
println("i:",i,"黑塞矩阵不可逆")
return nothing
end
d = -inv(h0) * g0
# 计算步长
#α0 = searcha(f,g,x0,g(,))
# upload data
δ = α0 .* d
x = x0 .+ δ
r = getR(x)
# 目标函数值
s = sum(r .^ 2)
if plot
println(x')
end
if debug
println("i:",i,",x:",x)
println("s:",s)
println("r0",r0)
println("J0",J0)
end
# 剪测是否达到要求的精度
if abs(s - s0)/max(1,s0) < acc
println("高斯牛顿法完成")
return x,s
end
x0 = x
r0 = r
s0 = s
end
println("达到最大迭代次数,结束高斯牛顿法")
return x0,s0
end
#Test
x,s = GaosiNewton(
(x,a,b) -> a + b*x^2,
(x,a,b) -> [1,x^2],
#(x,a,b) -> a + exp(b*x^2) ,
#(x,a,b) -> [1,exp(b+x^2)*x^2],
[0 1;1 0;3 2;5 4;6 4;7 5],
[100,100],
debug = false,
plot = true
)
#println(x)
#println(s)