前端机器学习——逻辑回归

692 阅读6分钟

前端机器学习——线性回归传送门

前端实现机器学习

机器学习越来越火,而作为一个不务正业的前端程序员!我当然要看一下这个机器学习,是个什么东西。

先说做什么

我们用机器学习可以做什么呢,他和我们前端有什么关系呢? 比方说我们做一个数据管理平台,老板要看数据情况,得到一些规律或者信息(几月赚钱多啊,卖啥赚钱多啊,下个月销售量估计怎样啊),这个时候后段给了你以前每一天的各种数据,某某日,啥啥啥,咋咋地买的好不好。我们不可能就给老板看这些点,像个芝麻烧饼一样。所以我们就需要用到机器学习,将这些点拟合成一条合适的线(最简单的线性回归),就显得很好。(别问为啥不是后端返回来线的截距和斜率,问就是自食其力),下面的我就举一个小栗子,写一个小demo,通过你不断选择色块,分析你喜欢的颜色特征,来预测在下一个色块的选择中你的选择是?在这里插入图片描述

再说怎么做

我是照着python代码手撸的js版本,其实没有什么难度,js与python相比,由于没有矩阵,我使用的是二维数组遍历进行运算的,其他也没什么,下面话不多说,直接贴代码。

python代码

// python代码
import numpy as np

def sigmoid(z):
   sigmoid = 1.0 / (1.0 + np.exp(-z))
   return sigmoid

# 梯度方向
def gradient(X, h, y):
   gradient = np.dot(X.T, (h - y)) / y.shape[0]
   return gradient

# 逻辑回归过程
def Logistic_Regression(x, y, lr=0.05, count=200):
   intercept = np.ones((x.shape[0], 1)) # 初始化截距为 1
   x = np.concatenate((intercept, x), axis=1)
   w = np.zeros(x.shape[1]) # 初始化参数为 0
   for i in range(count): # 梯度下降迭代
       z = np.dot(x, w) # 线性函数
       h = sigmoid(z)
       g = gradient(x, h, y) # 计算梯度
       w -= lr * g # 通过学习率 lr 计算步长并执行梯度下降

   return w # 返回迭代后的梯度和参数
//这是我手动选择色块得到的假数据,为什么是三维呢?因为我只存了两个色块三原色的差值
x = np.array([
   [-255, -255, -255],
   [-12, 43, -89],
   [-42, -25, 102],
   [7, 202, 81],
   [142, -67, -120],
   [100, 52, -6],
   [-19, -41, -24],
   [-108, 179, 78],
   [-192, 166, 27],
   [80, -30, -47],
   [53, 38, 140]
])
y = np.array([1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0])
w = Logistic_Regression(x, y)

javascript代码

// js代码
// 这个是假数据,注释掉了,因为把它整体封装成了一个方法
// const x = [
//     [-255, -255, -255],
//     [-12, 43, -89],
//     [-42, -25, 102],
//     [7, 202, 81],
//     [142, -67, -120],
//     [100, 52, -6],
//     [-19, -41, -24],
//     [-108, 179, 78],
//     [-192, 166, 27],
//     [80, -30, -47],
//     [53, 38, 140]
// ]
// const y = [1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0]
// const z = [-30, 100, -66]
// 入参x是之前色块的数据矩阵(条件),y是选择矩阵(结果),z是最后选择时色块的色差(最新条件)
export const MySigmod = function(x, y, z) {
    //sigmod函数
    const sigmod = function(z) {
        let c = []
        for(let i = 0; i < z.length; i++) {
            c.push(1/(1+Math.exp(-z[i])))
        }
        return c
    }
    //梯度方向
    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 Logistic_Regression(x, y, lr=0.05, count=500) {
        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 h = sigmod(z)
            let g = gradient(x, h, y)
            for(let i = 0; i < w.length; i++) {
                w[i] = w[i] - lr * g[i]
            }
            // l = loss(h, y)
        }
        return w
    }

    let w = Logistic_Regression(x,y)
    //使用求出的权重系数尽心选择
    let p = w[3]
    for(let i = 0; i < z.length; i++) {
        p = p + z[i] * w[i]
    }
    p = 1/(1+Math.exp(-p))
    return p
}

就算大功告成啦,看一下能不能成功呢!我之前选的都是浅色,所以应该选左面。估计结束! 在这里插入图片描述 没得问题,很成功哦!在这里插入图片描述

再说为什么

那么它的原理是什么呢,他怎样知道我想要的是浅色色块的呢。 这个就是用到了机器学习中第二基础的算法——逻辑回归(我自己觉得是第二基础,第一基础我觉得是线性回归,就只是我觉得啊~~),逻辑回归是一个名为回归实为分类的算法,用来二分类,输出的结果是一个概率(选某一边的概率),将之前的选择变成概率,拟合到sigmod函数上,而sigmod函数如下: ? g(z) = \frac{1}{(1+e^{-z})}\quad ? 而这个z就是我们熟悉(或者不熟悉)的线性回归函数模型了: ? z = w_0x_0+w_1x_1+w_2x_2+....+w_nx_n ? 这就是sigmod函数的图像,他的输入范围是正无穷到负无穷,输出范围是0到1,我们就用它来代表我们估计的概率,大于0.5我猜选右面,小于0.5我猜选左面(这个0.5不是定死的,在医疗中或者其他要求误差较严重的方面,这个值完全可以是0.3,0.2一类,反正输出的是概率) 在这里插入图片描述 那么我们就只需要求出这一系列的w就好啦,求得了这些系数,我们的公式就完整了,可以根据输入输出一个概率了! 那么这个系数怎么求呢? 首先我们假设w全是0,我们可以求出一个概率,这个概率和真实情况有了差距,怎么表示这种误差呢?在数学里使用似然函数,似然函数的值越大,误差越小。似然函数如下: ? \quad \prod_{i=1}^m p(y_i|x_i,\theta) ? 这个公式表示参数𝜃在给定输出为x的情况下的似然函数等于,在给定参数为𝜃和x{i},的情况下,取y{i}的概率。注意:此处的竖杠并不表示条件件概率,仅仅是一种取该值的含义。 其中P分为两种情况,P(y=0)=g(z)和P(y=1)=1-g(z),那么我们通过整合把它变成一个式子, ? L(\theta)=\quad \prod_{i=1}^m p(y_i|x_i,\theta)=\quad \prod_{i=1}^mg(z_i)^{y_i} (1-g(z_i))^{1-y_i} ? 其中g()就是上面的sigmod函数,z等于w{i}x{i}的累加,θ是w{i}的矩阵,然后将似然函数变成对数似然函数: ? l (\theta)= \sum_{i=1}^m (y_i\log g(z_i) +(1-y_i)\log (1-g(z_i)) ? 将这个式子称以-1/m变成梯度下降函数,然后对各个权重求导,得到对应的梯度(最快下降方向): ? l (\theta_j)= -\frac{1}{m}\quad \sum_{i=1}^m (z_i-y_i)*x_{ij} ? 具体求导过程可以去机器学习算法 --- 逻辑回归及梯度下降大神的博客那里看下。 现在我们也知道了梯度的公式,然后不断执行直到找到这个函数结果几乎不变就是我们想要的点了。