2021.12.31补充
sklearn中有现成的多项式回归,并不需要自己实现
需求分析
处理一段数据,需要求某点切线的斜率。想法是先用线性回归拟合出曲线的解析式,然后根据高中学的导数的定义求出某点的导数。
数据很整齐,但是是一条曲线,应该先把x进行升维然后进行更高次的线性回归,输出曲线解析式。然后根据导函数的定义输出导函数解析式。但是因为我没学过高等数学也没学过线性代数,sklearn也只会熟悉最基础的几个部分所以代码有不太成熟的地方就当是抛砖引玉。
关键代码
升维部分
初高中学过的
y
=
k
x
+
b
y = kx+b
y=kx+b图像时一条直线,实际数据很少会这么规整,所以要进行升维
(以三次多项式为例)
y
y
y=
k
1
k_1
k1
x
3
x^3
x3+
k
2
k_2
k2
x
2
x^2
x2+
k
3
k_3
k3
x
x
x+
b
b
b的形式
学过线代的就可以写成
y
=
w
x
+
b
y=wx+b
y=wx+b
像我这样没学过的,就先百度明白了再接着写吧
def __rise_x_dimension(self, x_data):
"""
多项式升维
:param n: 升维次数,默认四次
"""
res = []
temp_x_data = x_data.reshape(-1, 1)
for i in range(1, self.dimension + 1):
res.append(temp_x_data ** i)
return np.hstack(res)
求导部分
就是根据导数的定义了,没啥好说的。感觉有更好的办法,发现了再说。
def __get_k_s(self, point_x):
"""
获取切线方程
:param point_x:切点坐标
"""
for i in range(0, self.dimension):
self.k += (i + 1) * (point_x ** i) * self.w[i]
temp_x = self.__rise_x_dimension(np.array([point_x]).reshape(1, 1))
self.s = np.dot(temp_x, self.w) + self.b - self.k * point_x
全部代码
import numpy as np
from sklearn.linear_model import LinearRegression
import pandas as pd
import matplotlib.pyplot as plt
# 处理数据相关的代码,和整体没啥关系
def y_filter(raw):
res = raw[raw.iloc[:, 1] < 5e-7]
return res
class TangentSlope:
def __init__(self, x_data, y_data, dimension=4):
# 原始数据
self.x_raw_data = x_data
self.y_raw_data = y_data
# 用于训练的数据
self.x_data = None
# 多项式次数
self.dimension = dimension
# 拟合曲线解析式参数
self.w = None
self.b = None
# 拟合曲线的y值
self.y_hat = None
# 切线解析式参数(斜率、截距)
self.k = 0
self.s = 0
# 回归模型
self.line_regression = LinearRegression()
def __rise_x_dimension(self, x_data):
"""
多项式升维
:param n: 升维次数,默认四次
"""
res = []
temp_x_data = x_data.reshape(-1, 1)
for i in range(1, self.dimension + 1):
res.append(temp_x_data ** i)
return np.hstack(res)
def __get_k_s(self, point_x):
"""
获取切线方程
:param point_x:切点坐标
"""
for i in range(0, self.dimension):
self.k += (i + 1) * (point_x ** i) * self.w[i]
temp_x = self.__rise_x_dimension(np.array([point_x]).reshape(1, 1))
self.s = np.dot(temp_x, self.w) + self.b - self.k * point_x
def fit(self, show_hat=False, show_raw=False):
self.x_data = self.__rise_x_dimension(self.x_raw_data)
self.line_regression.fit(X=self.x_data, y=self.y_raw_data)
self.w = np.array(self.line_regression.coef_).reshape(-1, 1)
self.b = self.line_regression.intercept_
self.y_hat = np.dot(self.x_data, self.w) + self.b
if show_hat:
plt.plot(self.x_raw_data, self.y_hat, color='r')
if show_raw:
plt.scatter(self.x_raw_data, self.y_raw_data, color='b')
if show_hat or show_raw:
plt.show()
def get_tangent(self, point_x, show_chart=True):
"""
获取切线
:param show_chart: 是否显示图表
:param point_x:切点x坐标
:return:
"""
self.__get_k_s(point_x)
print("切线斜率", self.k)
if show_chart:
plt.plot(self.x_raw_data, self.y_raw_data, color='b')
tangent_y = self.k * self.x_raw_data + self.s
tangent_y = tangent_y.reshape(-1, 1)
plt.plot(self.x_raw_data, tangent_y, color="r")
plt.show()
if __name__ == '__main__':
#获取数据的x,y根据自己的实际业务
#PATH = "../data/idvg_comp.csv"
#raw_data = pd.read_csv(PATH)
#data_1 = y_filter(raw_data[["x1", "y1"]])
#x = np.log10(data_1["y1"].values)
#y = data_1["x1"].values
tangent_slope = TangentSlope(x, y, 2)
tangent_slope.fit(False, True)
tangent_slope.get_tangent(-7)