天天看点

前端机器学习——线性回归

前端机器学习——线性回归

前端机器学习——逻辑回归传送门

哈,现在我们再跳回机器学习的入门模型——线性回归,上一波我们使用逻辑回归完成了一个用户喜爱颜色预测的功能,那么我们这次就用线性回归完成一个将好多点拟合在一条线上的功能,嘿嘿,还是蛮实用,echarts.js本身是自带这个功能的。

前端机器学习——线性回归

但是本着能用就行 追本溯源的精神,我们来从零开始实现一波。

线性回归,就是通过这些点,找到一条合适的直线或者平面,或者超平面。

h = w 0 + w 1 x 1 + w 2 x 2 + . . . . . . + w n x n h = w_0+w_1x_1+w_2x_2+......+w_nx_n h=w0​+w1​x1​+w2​x2​+......+wn​xn​

我们的目的就是求出这一系列的w。那么接下来就说怎么找到合适的w。

我们直接在echart.js的官网上写一个z=9x+14y方程式加随机误差生成的五百个点,我们的目的就是要回归再根据这500个点再找到这条直线(或者平面或者超平面)
前端机器学习——线性回归

我们可以看到所有的点几乎都是几乎都是分布在z=9x+14y这个平面上的,但是上下还是有一点误差,同时我们能看到下面的输出[9.033991469275728, 13.966111482227832, 0.16362569478706737]

代表他线性回归后的式子是 z= 9.034x + 13.96y + 0.16,拟合回归程度还是可以的。

下面直接上主体函数代码,输入的x是入参数组,输入的y是输出数组,他和上次的sigmod函数——逻辑回归几乎是一摸一样的,唯一的区别就是少了个sigmod转化的过程,都是用的梯度下降法。

function MyGetline(x, y) {
    //我们使用梯度下降法,所以要求梯度方向
        const gradient = function(x, h, y) {
            let g = []
            for(let j = 0; j < x[0].length; j++) {
                let c = 0
                for(let i = 0; i < y.length; i++) {
                    c = c + x[i][j] * (h[i] - y[i])
                }
                c = c / y.length
                g.push(c)
            }
            return g
        }
        //线性回归过程x,y是入参和输出数组,lr是学习率(沿梯度方向下降距离),count是重复次数
        function Line_Regression(x, y, lr=0.000001, count=50000) {
            let w = []
            x.map(item => {
                item.push(1)
            })
            for(let i = 0; i < x[0].length; i++) {
                w.push(0)
            }
            for(let m = 0; m < count; m++) {
                let z = []
                for(let i = 0; i < x.length; i++) {
                    let item = 0
                    for(let j = 0; j < w.length; j++) {
                        item = item + x[i][j] * w[j]
                    }
                    z.push(item)
                }
                let g = gradient(x, z, y)
                for(let i = 0; i < w.length; i++) {
                    w[i] = w[i] - lr * g[i]
                }
            }
            return w
        }
    
        let w = Line_Regression(x,y)
        //返回w系数
        return w
    }
           

把下面的代码复制到echart.js的在线编辑器上去,就可以直接看效果并且随心修修改改了

(注:在3D散点图的实例提供的那个编辑界面有效,随便找个折线图实例进入编辑器是不行的哦 )

$.get(ROOT_PATH + 'data/asset/data/life-expectancy-table.json', function (data) {
    let symbolSize = 2.5;
    let mydata = []
    let x = []
    let y = []
    for(let i=0; i<500; i++) {
        let a = i * Math.random() * 10
        let b = i * Math.random() * 10
        let c = 9 * a + 14 * b + (Math.random() - 0.5) * i * 30
        let item = []
        item.push(a)
        item.push(b)
        item.push(c)
        let xitem = []
        xitem.push(a)
        xitem.push(b)
        x.push(xitem)
        y.push(c)
        mydata.push(item)
    }
    console.log(mydata)
    option = {
        grid3D: {},
        xAxis3D: {},
        yAxis3D: {},
        zAxis3D: {},
        dataset: {
            source: mydata
        },
        series: [
            {
                type: 'scatter3D',
                symbolSize: symbolSize
            }
        ]
    };

    myChart.setOption(option);
    //入参x是输入因变量数组,入参y是输出数组
    function MyGetline(x, y) {
    //梯度方向
        const gradient = function(x, h, y) {
            let g = []
            for(let j = 0; j < x[0].length; j++) {
                let c = 0
                for(let i = 0; i < y.length; i++) {
                    c = c + x[i][j] * (h[i] - y[i])
                }
                c = c / y.length
                g.push(c)
            }
            return g
        }
        //逻辑回归过程
        function Line_Regression(x, y, lr=0.0000001, count=50000) {
            let w = []
            x.map(item => {
                item.push(1)
            })
            for(let i = 0; i < x[0].length; i++) {
                w.push(0)
            }
            for(let m = 0; m < count; m++) {
                let z = []
                for(let i = 0; i < x.length; i++) {
                    let item = 0
                    for(let j = 0; j < w.length; j++) {
                        item = item + x[i][j] * w[j]
                    }
                    z.push(item)
                }
                let g = gradient(x, z, y)
                for(let i = 0; i < w.length; i++) {
                    w[i] = w[i] - lr * g[i]
                }
                // l = loss(h, y)
            }
            return w
        }
    
        let w = Line_Regression(x,y)
        //使用求出的权重系数进行选择
        console.log(w)
    }
    MyGetline(x,y)
});