我正在尝试实现具有梯度下降的线性回归,如本文(https://towardsdatascience.com/linear-regression-using-gradient-descent-97a6c8700931)所述。 我遵循了实现的原则,但是经过几次迭代,结果却溢出了。 我正尝试大致获得此结果:y = -0.02x + 8499.6。
代码:
package main
import (
"encoding/csv"
"fmt"
"strconv"
"strings"
)
const (
iterations = 1000
learningRate = 0.0001
)
func computePrice(m, x, c float64) float64 {
return m * x + c
}
func computeThetas(data [][]float64, m, c float64) (float64, float64) {
N := float64(len(data))
dm, dc := 0.0, 0.0
for _, dataField := range data {
x := dataField[0]
y := dataField[1]
yPred := computePrice(m, x, c)
dm += (y - yPred) * x
dc += y - yPred
}
dm *= -2/N
dc *= -2/N
return m - learningRate * dm, c - learningRate * dc
}
func main() {
data := readXY()
m, c := 0.0, 0.0
for k := 0; k < iterations; k++ {
m, c = computeThetas(data, m, c)
}
fmt.Printf("%.4fx + %.4f\n", m, c)
}
func readXY() ([][]float64) {
file := strings.NewReader(data)
reader := csv.NewReader(file)
records, err := reader.ReadAll()
if err != nil {
panic(err)
}
records = records[1:]
size := len(records)
data := make([][]float64, size)
for i, v := range records {
val1, err := strconv.ParseFloat(v[0], 64)
if err != nil {
panic(err)
}
val2, err := strconv.ParseFloat(v[1], 64)
if err != nil {
panic(err)
}
data[i] = []float64{val1, val2}
}
return data
}
var data = `km,price
240000,3650
139800,3800
150500,4400
185530,4450
176000,5250
114800,5350
166800,5800
89000,5990
144500,5999
84000,6200
82029,6390
63060,6390
74000,6600
97500,6800
67000,6800
76025,6900
48235,6900
93000,6990
60949,7490
65674,7555
54000,7990
68500,7990
22899,7990
61789,8290`
在这里它可以在GO操场上进行: https://play.golang.org/p/2CdNbk9_WeY
我需要解决什么才能获得正确的结果?
答案 0 :(得分:0)
为什么公式对一个数据集起作用而不对另一个数据集起作用?
除了sascha的评论外,这是查看梯度下降应用问题的另一种方法:该算法无法保证迭代产生的结果要比前一个更好,因此不一定会收敛到结果,因为:
dm
和dc
上的梯度m
和c
彼此独立地处理; m
根据dm
沿下降方向更新,而c
同时根据dc
沿下降方向更新-但具有一定的曲面z = f(m,c),则m
和c
之间的梯度在轴m
和c
之间可以具有相反的符号,因此,在更新m
或c
中的任何一个会收敛时,更新两个动作都偏离了最佳状态。m
和c
的更新的完全任意大小,由不确定的学习率和梯度。这样的更新很有可能超出目标函数的最小值,即使每次迭代都以更高的幅度重复进行此更新。