机器学习算法理论与代码实现——线性回归

一 线性模型

给定由n个属性描述的列向量 x=(x(1);x(2);...;x(n)) x = ( x ( 1 ) ; x ( 2 ) ; . . . ; x ( n ) ) ,其中 x(j) x ( j ) x x 在第 j j 个属性的取值。线性模型即为通过对属性进行线性组合的函数,即

f(x)=w0+w1x(1)+...+wnx(n)

写成向量形式如下:

f(x)=wTx f ( x ) = w T x

其中 列向量 w=(w0;w1;...;wn) w = ( w 0 ; w 1 ; . . . ; w n ) 列向量 x=(1;x(1);...;x(n)) x = ( 1 ; x ( 1 ) ; . . . ; x ( n ) ) 列向量 w w 确定后,模型随之确定。
线性模型形式简单,易于建模;
直观表达了各属性在预测中的重要性,因此具有很好的可解释性;

二 线性回归模型求解

对于给定的数据集 D={(x1,y1),(x2,y2),...,(xm,ym)} D = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x m , y m ) } ,其中 xi=(x(1)i;...;x(n)i) x i = ( x i ( 1 ) ; . . . ; x i ( n ) ) yi y i 为第 i i 个实例的实际值。“线性回归”试图学得一个线性模型以尽可能准确地预测实例的输出值,使之接近实际值。
关键问题是如何衡量两者之间的误差。这里采用均方误差作为性能度量,即利用最小二乘法来进行参数估计。

argminwJ(w)=12mi=1m(f(xi)yi)2

其实这里实质是用极大似然函数来进行参数估计,在一定假设前提下推导出上述目标函数进行参数估计,推导过程如下。
根据中心极限定理,认为误差项 ξ ξ 服从均值为零的高斯分布

P(ξi)=12πσexp(ξ2i2σ2) P ( ξ i ) = 1 2 π σ e x p ( − ξ i 2 2 σ 2 )

P(yi|xi;w)=12πσexp((yixi)22σ2) P ( y i | x i ; w ) = 1 2 π σ e x p ( − ( y i − x i ) 2 2 σ 2 )

由上可得似然函数,
L(w)=i=1nP(yi|xi;w) L ( w ) = ∏ i = 1 n P ( y i | x i ; w )

取对数,得对数似然函数
L(w)=nlog12πσ12σ2i=1m(f(xi)yi)2 L ( w ) = n l o g 1 2 π σ − 1 2 σ 2 ∑ i = 1 m ( f ( x i ) − y i ) 2

对上式取极大值等价于下式取极小值
J(w)=12mi=1m(f(xi)yi)2 J ( w ) = 1 2 m ∑ i = 1 m ( f ( x i ) − y i ) 2

推导完毕。
模型求解方法:矩阵直接求解和梯度下降法。
1 矩阵求解法
对于数据集 D D 中的每个实例组成一个矩阵,矩阵形式如下:
X=(1x1(1)...x1(n)1x2(1)...x2(n)......1xm(1).xm(n))=(1x1T1x2T..1xmT)

对应的实际值写成 列向量形式 y=(y1;y2;...;ym) y = ( y 1 ; y 2 ; . . . ; y m ) ,则有
w^=argminw^(yXw^)T(yXw^) w ^ ∗ = a r g m i n w ^ ( y − X w ^ ) T ( y − X w ^ )
上式argmin后面部分对 w^ w ^ 求导,另之等于零,
w^=(XTX)1XTy w ^ ∗ = ( X T X ) − 1 X T y
x^i=(1;xi) x ^ i = ( 1 ; x i ) 从而得到线性模型 f(x^i)=x^Tiw^ f ( x ^ i ) = x ^ i T w ^ ∗ ,或者 f(x^i)=w^Tx^i f ( x ^ i ) = w ^ ∗ T x ^ i
但是,现实情况中 XTX X T X 往 往 不 可 逆 ,通常原因有两种,一是高度共线性;二是数据特征过多而训练数据较少,此时可以通过正则化来解决。
2 梯度下降法
梯度下降是一种常用的一阶优化方法,是求解无约束优化问题的经典方法之一。对于连续可微函数上某一点,有各个方向导数,沿梯度方向的方向导数达到最大值,也就是说,梯度的方向是函数在这点增长最快的方向。
因此,我们可以得到如下结论:函数在某点的梯度是这样一个向量,它的方向与取得最大方向导数的方向一致,而它的模为方向导数的最大值。
所以我们可以沿反梯度方向不断一步一步迭代,得到局部极小点。当目标函数为凸函数时,局部极小点就是全局最小点,此时梯度下降法可确保收敛到全局最优解。
将损失函数对 列向量 w w 求导,得到 wj w j 的偏导:
J(w)wj=wj12mi=1m(f(xi)yi)2=1mi=1m(f(xi)yi)x(j)i,j=0,1,2,...,n ∂ J ( w ) ∂ w j = ∂ ∂ w j 1 2 m ∑ i = 1 m ( f ( x i ) − y i ) 2 = 1 m ∑ i = 1 m ( f ( x i ) − y i ) x i ( j ) , j = 0 , 1 , 2 , . . . , n
然后对各个分量都以下面形式更新 wj w j
wj=wjα1mi=1m(f(xi)yi)x(j)i w j = w j − α 1 m ∑ i = 1 m ( f ( x i ) − y i ) x i ( j )
有公式可以看出对于每一个分量进行一次迭代时计算了所有训练样本数据,这种称为 批量梯度下降。因此在数据量很大的时候,每次迭代都要遍历训练集一遍,开销会很大。
为改善上述情况,可以在每次迭代仅选择一个训练样本去计算代价函数的梯度,然后更新参数。即使是大规模数据集,随机梯度下降法也会很快收敛。这种方法称为 随机梯度下降。此时有,
wj=wjα(f(xi)yi)x(j)i w j = w j − α ( f ( x i ) − y i ) x i ( j )

比较:
批量梯度收敛速度慢,随机梯度收敛速度快。
批量梯度是在θ更新前对所有样例汇总误差,而随机梯度下降的权值是通过考查某个样本来更新的
批量梯度的开销大,随机梯度的开销小。

三 线性回归代码实现

import numpy as np
class MyLinearRegression():

    def __init__(self, n_iterations=10000, learning_rate=0.0001, regularization=None, gradient=True):
        '''初始化。是否正则化及L1L2的选择;选用梯度下降法还是正规方程法。梯度下降学习率以及迭代次数'''
        self.n_iterations = n_iterations
        self.learning_rate = learning_rate
        self.gradient = gradient
        if regularization == None:
            self.regularization = lambda x: 0
            self.regularization.grad = lambda x: 0
        else:
            self.regularization = regularization

    def initialize_weights(self, n_features):
        '''初始化权重.初始化模型参数,加入w0'''
        limit = np.sqrt(1 / n_features)
        w = np.random.uniform(-limit, limit, (n_features, 1))              #二维数组,n行一列。
        b = 0
        self.w = np.insert(w, 0, b, axis=0)                                

    def fit(self,X,y,):
        '''进行拟合'''
        m_samples, n_features = X.shape                                      # !!!
        self.initialize_weights(n_features)
        X = np.insert(X, 0, 1, axis=1)                                      #二维数组,每行前面加上元素1
        y = np.reshape(y, (m_samples, 1))                                    #二维数组,m 行一列
        self.training_errors = []
        if self.gradient == True:                                            #批量梯度下降
            for i in range(self.n_iterations):
                y_pred = X.dot(self.w)
                loss = np.mean(0.5 * (y_pred - y) ** 2)/m_samples + self.regularization(self.w)  # 矩阵运算
                '''mean()函数功能:求取均值
                经常操作的参数为axis,以m * n矩阵举例:
                axis 不设置值,对 m*n 个数求均值,返回一个实数
                axis = 0:压缩行,对各列求均值,返回 1* n 矩阵
                axis =1 :压缩列,对各行求均值,返回 m *1 矩阵
                np.mean(X,axis=0或者1,keepdims=True)
                '''
                self.training_errors.append(loss)
                w_grad = X.T.dot(y_pred - y) + self.regularization.grad(self.w)  # (y_pred - y).T.dot(X),计算梯度
                self.w = self.w - self.learning_rate * w_grad  # 更新权值w
        else:
            # 正规方程
            X = np.matrix(X)
            y = np.matrix(y)
            X_T_X = X.T.dot(X)
            X_T_X_I_X_T = X_T_X.I.dot(X.T)
            X_T_X_I_X_T_X_T_y = X_T_X_I_X_T.dot(y)
            self.w = X_T_X_I_X_T_X_T_y

    def predict(self, X):
        X = np.insert(X, 0, 1, axis=1)
        y_pred = X.dot(self.w)
        return y_pred
'''以二元为例,进行拟合'''
lr = MyLinearRegression()
X = np.array([[1,2],[2,4],[50,3],[23,59],[10,45],[10,61]])
y = np.array([3,6,53,82,55,71])
lr.fit(X,y)
y_test = lr.predict(np.array([[1,40],[2,6]]))
print(y_test)

这里用的是批量梯度下降法,其实也可以用随机梯度下降与小批量梯度下降,这里不再赘述。并且代码里省略了L1与L2正则化代码。
L1正则化下的损失函数

J(w)=12mi=1m(f(xi)yi)2+λW1 J ( w ) = 1 2 m ∑ i = 1 m ( f ( x i ) − y i ) 2 + λ ‖ W ‖ 1

其中 W1=wj ‖ W ‖ 1 = ∑ w j
L1正则化下的损失函数
J(w)=12mi=1m(f(xi)yi)2+λW22 J ( w ) = 1 2 m ∑ i = 1 m ( f ( x i ) − y i ) 2 + λ ‖ W ‖ 2 2

其中 W2=w2j ‖ W ‖ 2 = ∑ w j 2
L1正则化、L2正则化也称为Lasso正则化、Ridge正则化,其中 λλ 为模型的超参数。
L2 regularizer :使得模型的解偏向于 norm 较小的 W,通过限制 W 的 norm 的大小实现了对模型空间的限制,从而在一定程度上避免了 overfitting 。不过 ridge regression 并不具有产生稀疏解的能力,得到的系数 仍然需要数据中的所有特征才能计算预测结果,从计算量上来说并没有得到改观。
L1 regularizer : 它的优良性质是能产生稀疏性,导致 W 中许多项变成零。 稀疏的解除了计算量上的好处之外,更重要的是更具有“可解释性”。
关于正则化参考[ https://www.jianshu.com/p/a47c46153326]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值