局部加权线性回归(附实战代码python)

1、方法论

    局部加权线性回归(Local Weights Linear Regression)也是一种线性回归,不同的是,普通线性回归是全局线性回归,使用全部的样本计算回归系数。而局部加权线性回归,通过引入权值(核函数),在预测的时候,只使用与测试点相近的部分样本来计算回归系数。

    值得一提,该方法与kNN思想类似,都是用最近的若干样本点来做。


比如这样的曲线,用简单线性回归可以得到一条与样本具有最小均方差的直线,但这条直线显然不能代表图中数据所蕴含的细节规律,为了挖掘数据潜在特性,这里引入核函数,或者说权值,每次预测前都要计算一次回归系数,只使用测试点附件的部分样本点来进行计算。核函数如下


    这里分子项应该是平方(欧式距离),而不是绝对值,书中有误。其中w是一个对角方阵,方阵大小与x的样本数量相等,显然,这是一个均值为x,标准差为k的高斯函数,故与测试样本x越近的样本点,能够得到更高的权重,而远的点则权重很小。

    标准差k的选择可以遵循2sigma或者3sigma原则来。

    根据上面的理论,下面对线性回归的目标函数进行修改:


    注意w(i)是w(i,i),计算每一个样本点时候都要计算一次w矩阵

    求导并另导数为零可以得到:

    

2、Python实现

    有了上面的公式,python实现就很容易了,直接贴代码:

# 局部加权线性回归
# 增加了核函数,使用高斯核函数,相当于只用于当前数据点相近的部分数据计算回归系数
def linear_regression_local_weights(test_point, x, y, k):
    m = x.shape[0]
    weights = np.mat(np.eye(m))
    for i in range(m):
        s = np.sum((test_point - x[i]) * (test_point - x[i]).T)
        dif = np.sqrt(s)
        weights[i, i] = np.exp(dif / (-2.0 * k**2))

    xtx = x.T * weights * x
    if np.linalg.det(xtx) == 0:
        print("the matrix is singular, cannot do inverse")
        return 0
    w = xtx.I * x.T * weights * y  # (2,2)*(2,n)*(n,1)=(2,1)
    return test_point * w
# 局部加权线性回归,每次都要去计算weights和w,速度龟慢
# 200个数据也要7,8s
def lrlw_test():
    xd = np.linspace(0, 1, 200)
    yd = xd * 2 + 0.5 + 0.1*np.sin(xd * 50) + np.random.normal(0, 0.03, xd.shape[0])
    y_org = xd * 2 + 0.5 + 0.1*np.sin(xd * 50)
    y = yd.reshape(xd.shape[0], 1)
    y = np.mat(y)
    x = np.c_[xd, np.ones(xd.shape[0])]  # 在最后一列全部添加1,用来增加w0或者说偏置项b
    x = np.mat(x)
    y_predict = np.zeros(xd.shape[0])

    t1 = time.clock()  # datetime.datetime.now()
    for i in range(xd.shape[0]):
        y_predict[i] = linear_regression_local_weights(x[i], x, y, 0.08)  # 0.08可以得到0.999的相关性
    print(time.clock() - t1, "s")

    print(np.corrcoef(y_org, y_predict))
    plt.scatter(xd, yd, marker=".", color="b")
    plt.plot(xd, y_predict, "r")
    plt.show()
实现方法和用公式计算最小二乘差不多。只是速度太慢了,每次都要计算一次核函数权值,每次都要计算一次回归系数,500个样本点它给我跑到5,6秒钟去了。

200个样本点,最后运行效果:

1.3961943469164886 s
[[ 1.          0.99924515]
 [ 0.99924515  1.        ]]


小结一下:

优点:用Python实现简单,容易理解,应该可以拟合任意的连续曲线

缺点:每次都要计算权值,效率很低





参考链接:

https://blog.csdn.net/gadwgdsk/article/details/79769206
https://blog.csdn.net/z_feng12489/article/details/80213739
https://blog.csdn.net/lanchunhui/article/details/88261494

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值