跳转至

多元线性回归的公式与矢量化代码实现方法(笔记)

以房价预测为例

面积(sqft) 卧室数 楼层数 房龄 价格(千美元)
2104 5 1 45 460
1416 3 2 40 232
852 2 1 35 178
  • 一共有三组样本,m=3;每组样本的x有4个特征,分别是面积,卧室数,楼层数,房龄。价格为目标值y。

  • \[ f_{\mathbf{w},b}(\mathbf{x}) = \mathbf{w} \cdot \mathbf{x} + b \tag{1} \]

1.创建样本矩阵与参数变量初始化

\[\mathbf{X} = \begin{pmatrix} x^{(0)}_0 & x^{(0)}_1 & \cdots & x^{(0)}_{n-1} \\ x^{(1)}_0 & x^{(1)}_1 & \cdots & x^{(1)}_{n-1} \\ \cdots \\ x^{(m-1)}_0 & x^{(m-1)}_1 & \cdots & x^{(m-1)}_{n-1} \end{pmatrix}\]
X_train = np.array([[2104, 5, 1, 45], [1416, 3, 2, 40], [852, 2, 1, 35]])
y_train = np.array([460, 232, 178])
\[ \mathbf{w} = \begin{pmatrix} w_0 \\ w_1 \\ \cdots\\ w_{n-1} \end{pmatrix} \]
  • b为标量
#此初始化值接近最优
b_init = 785.1811367994083
w_init = np.array([ 0.39133535, 18.75376741, -53.36032453, -26.42131618])

2.计算成本函数

\[ J(\mathbf{w},b) = \frac{1}{2m} \sum\limits_{i = 0}^{m-1} \big(f_{\mathbf{w},b}(\mathbf{x}^{(i)}) - y^{(i)}\big)^2 \tag{2} \]
\[ f_{\mathbf{w},b}(\mathbf{x}^{(i)}) = \mathbf{w} \cdot \mathbf{x}^{(i)} + b \tag{3} \]

(2)为多变量下的成本函数,(3)为多变量下的回归方程。

def compute_cost(X, y, w, b):  #定义一个函数用于计算成本
    m = X.shape[0]             #将样本数赋给m
    cost = 0.0
    for i in range(m):         #用一个for循环计算每组样本预测值与目标值差的平方并求和
        f_wb_i = np.dot(X[i], w) + b         #计算样本预测值  
        cost = cost + (f_wb_i - y[i])**2       
    cost = cost / (2 * m)                      
    return cost

3.计算多变量的梯度

\[ \begin{align} \frac{\partial J(\mathbf{w},b)}{\partial w_j} &= \frac{1}{m} \sum\limits_{i=0}^{m-1} \big(f_{\mathbf{w},b}(\mathbf{x}^{(i)}) - y^{(i)}\big) x_{j}^{(i)} \tag{4} \\ \frac{\partial J(\mathbf{w},b)}{\partial b} &= \frac{1}{m} \sum\limits_{i=0}^{m-1} \big(f_{\mathbf{w},b}(\mathbf{x}^{(i)}) - y^{(i)}\big) \tag{5} \end{align} \]
def compute_gradient(X, y, w, b):   #定义一个函数用于计算梯度
    m,n = X.shape                           #样本数赋给m,特征数赋给n
    dj_dw = np.zeros((n,))                  #初始化梯度
    dj_db = 0.

    for i in range(m):                            
        err = (np.dot(X[i], w) + b) - y[i]   #计算每一组样本预测与目标之差
        for j in range(n):                         
            dj_dw[j] = dj_dw[j] + err * X[i, j]    #将目标与预测之差乘特征x得到特征w梯度的中间量
        dj_db = dj_db + err           #得到J对于b梯度的中间量             
    dj_dw = dj_dw / m                 #得到J对于w梯度的向量               
    dj_db = dj_db / m                 #得到J对于b的梯度              

    return dj_db, dj_dw

4.计算多变量的梯度下降

\[ \begin{align*} \text{repeat}&\text{ until convergence:}\;\{ \\[-2mm] & w_j = w_j - \alpha \frac{\partial J(\mathbf{w},b)}{\partial w_j} \tag{6} \quad \text{for } j=0..n-1 \\[1mm] & b\ \ = b - \alpha \frac{\partial J(\mathbf{w},b)}{\partial b} \\ \} \end{align*} \]
def gradient_descent(X, y, w_in, b_in, cost_function, gradient_function, alpha, num_iters):       #定义一个函数来迭代W与b,num_iters表示迭代次数
    # 用于在每次迭代中存储代价 J 和 w 的数组,主要用于后续绘图
    J_history = []
    w = copy.deepcopy(w_in)  # 避免在函数内修改全局变量 w
    b = b_in

    for i in range(num_iters):

        # 计算梯度并更新梯度
        dj_db,dj_dw = gradient_function(X, y, w, b)   # 就是上一步中计算梯度的公式

        # 使用 w、b、学习率 alpha 和梯度更新参数
        w = w - alpha * dj_dw               # 向量
        b = b - alpha * dj_db               # 标量

        # 在每次迭代时保存成本 J
        if i<100000:      # 防止资源耗尽
            J_history.append( cost_function(X, y, w, b))

        # 每隔一定步数打印一次代价,步数为迭代次数除以10(向上取整),最多打印 10 次;若迭代次数少于 10,则按实际次数打印
        if i% math.ceil(num_iters / 10) == 0:
            print(f"Iteration {i:4d}: Cost {J_history[-1]:8.2f}   ")

    return w, b, J_history # 返回最终的 w、b 以及用于绘图的 J 历史

编辑于9月22日