欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

手写算法-Python代码实现非线性回归

程序员文章站 2024-01-18 11:59:58
手写算法-Python代码实现非线性回归生成非线性数据集1、用线性回归拟合2、多项式拟合sklearn实现,校验系数的结果总结生成非线性数据集前面我们介绍了Python代码实现线性回归,今天,我们来聊一聊当数据呈现非线性时,这时我们继续用线性表达式去拟合,显然效果会很差,那我们该怎么处理?继续上实例(我们的代码里用到的数据集尽量直接由Python生成,因此,是可以全部跑通的,有需要的同学,建议大家粘贴复现一下,多思考,多动手,才可以学的更好。)import numpy as npfrom matpl...

生成非线性数据集

前面我们介绍了Python代码实现线性回归,今天,我们来聊一聊当数据呈现非线性时,这时我们继续用线性表达式去拟合,显然效果会很差,那我们该怎么处理?继续上实例(我们的代码里用到的数据集尽量直接由Python生成,因此,是可以全部跑通的,有需要的同学,建议大家粘贴复现一下,多思考,多动手,才可以学的更好。)

import numpy as np
from matplotlib import pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

#生成如下数据集
a= np.arange(1,11)
b=np.array([4500,5000,6000,8000,11000,15000,20000,30000,50000,100000])
data = np.c_[a,b]

#给x,y分别添加维度
x = data[:,0,np.newaxis]
y=data[:,1,np.newaxis]
plt.scatter(x,y)
plt.show()

手写算法-Python代码实现非线性回归

1、用线性回归拟合

数据的分布如上图所示,这时候如果继续使用线性回归去拟合,这里继续使用上篇文章Python手写的类,和sklearn里面实现是一样的。
链接: 手写算法-Python代码推广多元线性回归

class normal():
    def __init__(self):
        pass

    def fit(self,x,y):
        m=x.shape[0]
        X = np.concatenate((np.ones((m,1)),x),axis=1)
        xMat=np.mat(X)
        yMat=yMat =np.mat(y.reshape(-1,1))

        xTx=xMat.T*xMat
        #xTx.I为xTx的逆矩阵
        ws=xTx.I*xMat.T*yMat
        return ws


model=normal()
w = model.fit(x,y)

#生成2个点画图
x_test=np.array([[1],[10]])
y_test = w[0] + x_test * w[1]


ax1= plt.subplot()
ax1.plot(x_test,y_test,c='r',label='线性回归拟合线')
ax1.scatter(x,y,c='b',label='真实分布')
ax1.legend()
plt.show()

手写算法-Python代码实现非线性回归
可以看出拟合的效果很差,这里如果用

手写算法-Python代码实现非线性回归
这种表达式去拟合应该会更好

2、多项式拟合

这里和大家介绍一个
#生成多项式
from sklearn.preprocessing import PolynomialFeatures
实现的功能是给X增加维度,具体的可以看官网或者看看我的这篇文章,里面有实现的原理解析,看一下明白了。
链接: 代码系列-python实现PolynomialFeatures(多项式)
我们继续用Python实现:

def multi_feature(x,n):
    c = np.empty((x.shape[0],0)) #np.empty((3,1))并不会生成一个3行1列的空数组,np.empty((3,0))才会生成3行1列空数组
    for i in range(n+1):
        h=x**i
        c=np.c_[c,h]
    return c

#先设置n=2
x_1 = multi_feature(x,2)
x_1   #输出变化后的x

手写算法-Python代码实现非线性回归

model=normal()
#用新生成的x作为输入
w = model.fit(x_1,y)

报错了!!!
LinAlgError: Singular matrix
这个错误代表在对numpy的矩阵用np.linalg.inv方法时报错,也就是无法求逆矩阵,难道要屈服用sklearn吗?

不行!!

第一时间返回去看我们写的类,破案了!问题很简单,python写的类里面,我们给x添加了偏置,在这个生成的多项式x_1中,本身就有一列1,这样的话就有2列1,变成了一个非满秩矩阵,因此不需要再添加偏置,修改代码如下:

class normal():
    def __init__(self):
        pass

    def fit(self,x,y):
        #x_1中已经生成了一列1,不需要再加偏置,因此注释掉这2列。
        
        
        #m=x.shape[0]
        #X = np.concatenate((np.ones((m,1)),x),axis=1) 
        xMat=np.mat(x)
        yMat=yMat =np.mat(y.reshape(-1,1))

        xTx=xMat.T*xMat
        #xTx.I为xTx的逆矩阵
        ws=xTx.I*xMat.T*yMat
        return ws

model=normal()
#用新生成的x作为输入
w = model.fit(x_1,y)
w

手写算法-Python代码实现非线性回归

这次没有问题了。(为了检查参数是否正确,我又马上调用了sklearn来跑了一遍,先透露结论:系数没错,后面上sklearn的结果)

画图看这次的拟合效果:

#计算x_1的拟合效果,下面是矩阵乘法
y_1 = np.dot(x_1,w) 

ax1= plt.subplot()
ax1.plot(x,y_1,c='r',label='n=2时,拟合效果图')
ax1.scatter(x,y,c='b',label='真实分布图')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

手写算法-Python代码实现非线性回归
效果好很多了,设置n=5

#设置n=5
x_2 = multi_feature(x,5)


model=normal()
#用新生成的x_2作为输入,重新拟合
w = model.fit(x_2,y)


#计算x_2的拟合效果,下面是矩阵乘法
y_2 = np.dot(x_2,w) 
ax1= plt.subplot()
ax1.plot(x,y_2,c='r',label='n=5时,拟合效果图')
ax1.scatter(x,y,c='b',label='真实分布图')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

手写算法-Python代码实现非线性回归

已经很完美了,由于点太少,显得拟合曲线不是那么平滑,多传入一些x值,

x_test = np.linspace(1,10,100)
x_3 = multi_feature(x_test,5)

#生成预测值y_3
y_3 = np.dot(x_3,w) 
ax1= plt.subplot()
ax1.plot(x_test,y_3,c='r',label='n=5时,拟合效果图')
ax1.scatter(x,y,c='b',label='真实分布图')
ax1.legend(prop = {'size':15}) #此参数改变标签字号的大小
plt.show()

手写算法-Python代码实现非线性回归

sklearn实现,校验系数的结果

最后附上sklearn检验系数的结果,完全一样的:

from sklearn.linear_model import LinearRegression
model = LinearRegression()
model.fit(x_2, y)
print('截距为:',model.intercept_,'\n')
print('系数为:',model.coef_,'\n')
print(w)

手写算法-Python代码实现非线性回归

总结

1、这篇文章主要告诉我们,做回归模型时,要了解数据,不能上来就调用sklearn里面的线性回归包,要根据数据的分布,选择合适的算法包,有时候还要对X特征进行一些预处理工作。

2、平时做机器学习还是调包,因为自己写的有很多不足的地方,且很难做到推广,但是,学习的过程中,还是建议多研究一下原理,这样可以走得更远。

3、大家有什么问题需要交流,我一定知无不言,期待一起进步。

本文地址:https://blog.csdn.net/weixin_44700798/article/details/110584147