关于多项式函数Python的信息

Python 中的函数拟合很多业务场景中,我们希望通过一个特定的函数来拟合业务数据,以此来预测未来数据的变化趋势 。(比如用户的留存变化、付费变化等)
本文主要介绍在 Python 中常用的两种曲线拟合方法:多项式拟合 和 自定义函数拟合 。
通过多项式拟合,我们只需要指定想要拟合的多项式的最高项次是多少即可 。
运行结果:
对于自定义函数拟合,不仅可以用于直线、二次曲线、三次曲线的拟合,它可以适用于任意形式的曲线的拟合,只要定义好合适的曲线方程即可 。
运行结果:
多项式拟合平方误差怎么求线性模型(二)之多项式拟合
1. 多项式拟合问题
??多项式拟合(polynominal curve fitting)是一种线性模型,模型和拟合参数多项式函数Python的关系是线性的 。多项式拟合的输入是一维的,即x=xx=x , 这是多项式拟合和线性回归问题的主要区别之一 。
??多项式拟合的目标是构造输入xx的MM阶多项式函数,使得该多项式能够近似表示输入xx和输出yy的关系,虽然实际上xx和yy的关系并不一定是多项式 , 但使用足够多的阶数,总是可以逼近表示输入xx和输出yy的关系的 。
??多项式拟合问题的输入可以表示如下:
D={(x1,y1),(x2,y2),...,(xi,yi),...,(xN,yN)}xi∈Ryi∈R
D={(x1,y1),(x2,y2),...,(xi,yi),...,(xN,yN)}xi∈Ryi∈R
??目标输出是得到一个多项式函数:
f(x)=w1x1 w2x2 wixi ... wMxM b=(∑i=1Mwixi) b
f(x)=w1x1 w2x2 wixi ... wMxM b=(∑i=1Mwixi) b
其中MM表示最高阶数为MM 。
??可见在线性拟合的模型中,共包括了(M 1)(M 1)个参数 , 而该模型虽然不是输入xx的线性函数,但却是(M 1)(M 1)个拟合参数的线性函数,所以称多项式拟合为线性模型 。对于多项式拟合问题,其实就是要确定这(M 1)(M 1)个参数 , 这里先假设阶数MM是固定的(MM是一个超参数,可以用验证集来确定MM最优的值 , 详细的关于MM值确定的问题,后面再讨论),重点就在于如何求出这(M 1)(M 1)个参数的值 。
2.优化目标
??多项式拟合是利用多项式函数逼近输入xx和输出yy的函数关系,通过什么指标来衡量某个多项式函数的逼近程度呢?(其实这就是误差/损失函数) 。拟合/回归问题常用的评价指标是均方误差(在机器学习中的模型评估与度量博客中,多项式函数Python我进行了介绍) 。多项式拟合问题也同样采用该评价指标,以均方误差作为误差/损失函数,误差函数越小,模型越好 。
E(w,b)=1N∑i=1N[f(xi)?yi]2
E(w,b)=1N∑i=1N[f(xi)?yi]2
【关于多项式函数Python的信息】??系数1N1N是一常数,对优化结果无影响 , 可以去除 , 即将均方误差替换为平方误差:
E(w,b)=∑i=1N[f(xi)?yi]2
E(w,b)=∑i=1N[f(xi)?yi]2
?? 到这里,就成功把多项式拟合问题变成了最优化问题 , 优化问题可表示为:
argminw,bE(w,b)
arg?minw,b?E(w,b)
即需要求得参数{w1,...,wM,b}{w1,...,wM,b}的值,使得E(w,b)E(w,b)最小化 。那么如何对该最优化问题求解呢?
3. 优化问题求解
3.1 求偏导,联立方程求解
?? 直观的想法是 , 直接对所有参数求偏导,令偏导为0 , 再联立这M 1M 1个方程求解(因为共有M 1M 1个参数,故求偏导后也是得到M 1M 1个方程) 。
E(w,b)=∑i=1N[f(xi)?yi]2=∑i=1N[(w1x1i w2x2i wixji ... wMxMi b)?yi]2
E(w,b)=∑i=1N[f(xi)?yi]2=∑i=1N[(w1xi1 w2xi2 wixij ... wMxiM b)?yi]2
利用E(w,b)E(w,b)对各个参数求偏导,如下:
?E(w,b)?wj?E(w,b)?b=2∑i=1N[(w1x1i w2x2i wixji ... wMxMi b)?yi]xji=2∑i=1N[(w1x1i w2x2i wixji ... wMxMi b)?yi]
?E(w,b)?wj=2∑i=1N[(w1xi1 w2xi2 wixij ... wMxiM b)?yi]xij?E(w,b)?b=2∑i=1N[(w1xi1 w2xi2 wixij ... wMxiM b)?yi]
求导之后,将各个点(xi,yi)(xi,yi)的值带入偏导公式,联立方程求解即可 。
??针对该解法,可以举个例子详细说明,比如有两个点(2,3),(5,8)(2,3),(5,8),需要利用二阶多项式f(x)=w1x w2x2 bf(x)=w1x w2x2 b拟合 。求解过程如下:
该二阶多项式对参数求偏导得到
?E(w,b)?wj?E(w,b)?b=2∑i=12[(w1x1i w2x2i b)?yi]xji=[(w1x1 w2x21 b)?y1]xj1 [(w1x2 w2x22 b)?y2]xj2=2∑i=12[(w1x1i w2x2i b)?yi]=[(w1x1 w2x21 b)?y1] [(w1x2 w2x22 b)?y2]
?E(w,b)?wj=2∑i=12[(w1xi1 w2xi2 b)?yi]xij=[(w1x1 w2x12 b)?y1]x1j [(w1x2 w2x22 b)?y2]x2j?E(w,b)?b=2∑i=12[(w1xi1 w2xi2 b)?yi]=[(w1x1 w2x12 b)?y1] [(w1x2 w2x22 b)?y2]
将点(2,3),(5,8)(2,3),(5,8)带入方程 , 可以得到3个方程,
2b 7w1 29w2=117b 29w1 133w2=4629b 133w1 641w2=212
2b 7w1 29w2=117b 29w1 133w2=4629b 133w1 641w2=212
联立这三个方程求解 , 发现有无穷多的解,只能得到3w1 21w2=53w1 21w2=5 , 这三个方程是线性相关的,故没有唯一解 。
??该方法通过求偏导,再联立方程求解,比较复杂,看着也很不美观 。那么有没有更加方便的方法呢?
3.2 最小二乘法
?? 其实求解该最优化问题(平方和的最小值)一般会采用最小二乘法(其实最小二乘法和求偏导再联立方程求解的方法无本质区别 , 求偏导也是最小二乘法 , 只是这里介绍最小二乘的矩阵形式而已) 。最小二乘法(least squares),从英文名非常容易想到,该方法就是求解平方和的最小值的方法 。
??可以将误差函数以矩阵的表示(NN个点,最高MM阶)为:
∥Xw?y∥2
‖Xw?y‖2
其中 , 把偏置bb融合到了参数ww中 ,
w={b,w1,w2,...,wM}
w={b,w1,w2,...,wM}
XX则表示输入矩阵,
??????11...1x1x2...xNx21x22...x2N............xM1xM2...xMN??????
[1x1x12...x1M1x2x22...x2M...............1xNxN2...xNM]
yy则表示标注向量,
y={y1,y2,...,yN}T
y={y1,y2,...,yN}T
因此,最优化问题可以重新表示为
minw∥Xw?y∥2
minw‖Xw?y‖2
对其求导,
?∥Xw?y∥2?w=?(Xw?y)T(Xw?y)?w=?(wTXT?yT)(Xw?y)?w=?(wTXTXw?yTXw?wTXTy yTy)?w
?‖Xw?y‖2?w=?(Xw?y)T(Xw?y)?w=?(wTXT?yT)(Xw?y)?w=?(wTXTXw?yTXw?wTXTy yTy)?w
在继续对其求导之前,需要先补充一些矩阵求导的先验知识(常见的一些矩阵求导公式可以参见转载的博客),如下:
?xTa?x=a?ax?x=aT?xTA?x=Ax ATx
?xTa?x=a?ax?x=aT?xTA?x=Ax ATx
根据上面的矩阵求导规则,继续进行损失函数的求导
?∥Xw?y∥2?w=?(wTXTXw?yTXw?wTXTy yTy)?w=XTXw (XTX)Tw?(yTX)T?XTy=2XTXw?2XTy
?‖Xw?y‖2?w=?(wTXTXw?yTXw?wTXTy yTy)?w=XTXw (XTX)Tw?(yTX)T?XTy=2XTXw?2XTy
其中XTXw=(XTX)TwXTXw=(XTX)Tw.令求导结果等于0,即可以求导问题的最小值 。
2XTXw?2XTy=0w=(XTX)?1XTy
2XTXw?2XTy=0w=(XTX)?1XTy
??再利用最小二乘法的矩阵形式对前面的例子进行求解,用二阶多项式拟合即两个点(2,3),(5,8)(2,3),(5,8) 。
表示输入矩阵 XX和标签向量yy
X=[1125425]y=[38]T
X=[1241525]y=[38]T
计算XTXXTX
XTX=???272972913329133641???
XTX=[272972913329133641]
矩阵求逆,再做矩阵乘法运算
但 XTXXTX不可逆,故无唯一解 。
??关于矩阵的逆是否存在,可以通过判断矩阵的行列式是否为0(det(A)=?0det(A)=?0 来判断,也可以通过初等行变换,观察矩阵的行向量是否线性相关,在这个例子下 , 矩阵不可逆,故有无穷多解 。但如果新增一个点(4,7)(4,7) , 则就可以解了 。
??其实这和数据集的点数和选择的阶数有关,如果点数小于阶数则会出现无穷解的情况 , 如果点数等于阶数,那么刚好有解可以完全拟合所有数据点,如果点数大于阶数 , 则会求的近似解 。
??那么对于点数小于阶数的情况 , 如何求解?在python的多项式拟合函数中是可以拟合的 , 而且效果不错 , 具体算法不是很了解,可以想办法参考python的ployfit()函数的实现 。
4. 拟合阶数的选择
?? 在前面的推导中,多项式的阶数被固定了,那么实际场景下应该如何选择合适的阶数MM呢?
一般会选择阶数MM小于点数NN
把训练数据分为训练集合验证集,在训练集上,同时用不同的MM值训练多个模型,然后选择在验证集误差最小的阶数script type="math/tex" id="MathJax-Element-5573"M/script
python牛顿法求多项式的根#includeiostream.h
#includemath.h
#includeconio.h
const int N=200;
//带入原函数后所得的值
double f(float x)
{
return (x*x*x-1.8*x*x 0.15*x 0.65);
}
//带入一阶导函数后所得的值
double f1(double x)
{
return (3*x*x-3.6*x 0.15);
}
//牛顿迭代函数
double F(double x)
{
double x1;
x1=x-1.0*f(x)/f1(x);
return (x1);
}
void main()
{
double x0,D_value,x1,y[4];
int k=0,count=0;
for(;;)
{
if(count==3)break;
cout"输入初始值:";
cinx0;
do
{
k;
x1=F(x0);
D_value=https://www.04ip.com/post/fabs(x1-x0);
x0=x1;
}
while((D_value0.000005)(k=N));
for(int j=0,flag=0;jcount;j)
{
if(fabs(y[j]-x1)0.000005)
{flag=1;
cout"该数值附近的根已经求出,请重新换近似值"endl;
break;
}
}
if(flag==1)
continue;
else
{
cout"方程的一个根:"x1","" 迭代次数为:"kendl;
y[count]=x1;
count;
}
//else
//cout"计算失败!"endl;
}
}
//你的程序其实没问题 , 牛顿迭代法本身循环一次只能找到一个答案,只要再建一个循环控制使
//用迭代法的次数和判断根的个数就行 。我又加了一个判断是否有重复的根的循环 。
//希望能对你有所帮助 。
pytorch全连接层计算时间短1.读取数据
首先,引入必要的头文件 , 并从文件中读入数据:
import pandas as pd import numpy as np import matplotlib.pyplot as plt %matplotlib inline import torch import torch.nn as nn from torch.autograd import Variable df = pd.read_csv('data/AirPassengers.csv') plt.plot(df['#Passengers']) plt.show()
程序输出如下图所示:
2.归一化
无论机器学习还是深度学习,使用哪一种框架,归一化都是必要环节 。归一化的目标是将每一维特征压缩到一定范围之内,以免不同特征因取值范围不同而影响其权重 。非常大或非常小的值搭配上不恰当的学习率,往往使得收敛过慢 , 或者因每次调整的波动太大最终无法收敛 。归一化去除了这些不稳定因素 。
归一化的具体做法是将某一列特征转换成均值为 0、标准差为1的数据,在图像处理过程中,也常把0-255之间的颜色值转换为0-1之间的小数 。
本例中使用了均值和标准差编写了归一化和反归一化函数:
def feature_normalize(data): mu = np.mean(data,axis=0) # 均值 std = np.std(data,axis=0) # 标准差 return (data - mu)/std def feature_unnormalize(data, arr): mu = np.mean(data,axis=0) std = np.std(data,axis=0) return arr * stdmu
3.提取新特征
提取新特征是指从现有特征中提取更多可以代入模型的信息,从而生成新特征,本例中的数据包括两列,第一列“Month”是字符串类型的时间,第二列“#Passengers”是乘客量,也就是需要预测的数据y 。下面通过拆分和类型转换 , 从第一列中提取具体的年“year”和月“mon”,将索引列变为特征“x”,并使用上面定义的函数实现归一化功能 。
df['year'] = df['Month'].apply(lambda x: float(x[:4])) df['mon'] = df['Month'].apply(lambda x: float(x[5:])) df['x'] = feature_normalize(df.index) df['y'] = feature_normalize(df['#Passengers']) df['year'] = feature_normalize(df['year']) df['mon'] = feature_normalize(df['mon']) df['real'] = feature_unnormalize(df['#Passengers'], df['y'])
处理后的数据如下图所示:
4.处理缺失值和异常值
处理缺失值和异常值也是特征工程的重要环节 , 有时花费的时间比建模还多 。处理缺失值的常用方法是删除重要特征缺失的item,或者用均值,前后值填充;处理异常值是监测数据中不正常的值,并做出相应处理,由于本例中数据比较“干净” , 无需做缺失值和异常值处理 。
5.向量化
向量化是将读出的数据转换成模型需要的数据格式,根据不同的模型做法不同,本例中的向量化将在后面的模型部分实现 。
6.切分训练集和测试集
训练前还需要把数据切分成训练集和测试集,以避免过拟合,本例中将70%的数据用于训练,最终模型将对所有数据预测并做图 。
TRAIN_PERCENT = 0.7 train_size = int(len(df) * TRAIN_PERCENT) train = df[:train_size]
拟合直线
拟合程序分成三部分:定义模型、优化器和误差函数;训练模型;预测并做图 。
1.定义模型、优化器、误差函数
模型继承自mm.Module,并实现了两个核心函数,init用于初始化模型结构,forward用于定义前向传播的过程 。本例中实现了最为简单的模型,其中只包含一个全连接层 , 使用nn.Linear定义,torch.nn中定义了常用的网络层实现 。
class LinearRegression(nn.Module): def __init__(self): super(LinearRegression, self).__init__() self.linear = nn.Linear(1, 1) # 输入和输出的维度都是1 def forward(self, x): x = self.linear(x) return x model = LinearRegression() criterion = nn.MSELoss() # 损失函数:均方误差 optimizer = torch.optim.SGD(model.parameters(), lr=0.001) # 优化算法:随机梯度下降
损失函数使用了均方误差 MSELoss,它计算的是预测值与真值之差平方的期望值,MSELoss也是回归中最常用的损失函数,torch.nn中实现了一些常用的损失函数,可以直接使用,
优化的目标是更好地更新参数,使模型快速收敛 。优化算法就是调整模型参数更新的策略,优化器是优化算法的具体实现 。本例中优化器optimizer使用了最基础的随机梯度下降optim.SGD优化方法,torch.optim中定义了常用的优化器 。在参数中设置了学习率为0.001,并将模型的参数句柄传入优化器 , 优化器后期将调整这些参数 。
注意:学习率是一个重要参数,最好从小到大设置,如果设置太大,可能造成每次对参数修改过大,造成抖动 , 使得最终无法收敛 。
2.训练模型
训练之前,先把数据转换成模型需要的数据格式,将pandas的数据格式转换为float32格式的Tensor张量,然后用unsqueeze扩展维度到2维(unsqueeze已在上一篇详细介绍) 。
x = torch.unsqueeze(torch.tensor(np.array(train['x']), dtype=torch.float32), dim=1) y = torch.unsqueeze(torch.tensor(np.array(train['y']), dtype=torch.float32), dim=1) for e in range(10000): inputs = Variable(x) target = Variable(y) out = model(inputs) # 前向传播 loss = criterion(out, target) # 计算误差 optimizer.zero_grad() # 梯度清零 loss.backward() # 后向传播 optimizer.step() # 调整参数 if (e 1) % 1000 == 0: # 每1000次迭代打印一次误差值 print('Epoch:{}, Loss:{:.5f}'.format(e 1, loss.item()))
后面的循环部分进行了10000次迭代,也就是说将所有数据放进模型训练了10000次,从而使模型收敛 。每一次循环之中,将x,y分别转换成变量Variable格式 。
然后进行前先传播 , model(inputs)调用的是nn.Module 的call()函数(call是Python类中的一个特殊方法,如果类中定义了此方法,可以通过实例名加括号的方式调用该方法)父类的call()调用了前向函数forward()将数据传入层中处理 。
接下来是误差函数和优化器配合调整模型参数,此处到底修改了哪些值,又是如何修改的,是最难理解的部分 。先通过定义的误差函数计算误差,从loss值可以看到每一次迭代之后误差的情况 。
下一步是优化器清零,调用优化器的zero_grad方法,清除了model.parameters中的梯度grad 。
之后是反向传播,误差函数的backward,调用了torch.autograd.backward()函数,backward()是上面定义的forward()的反向过程,对每层每一个参数求导,并填充在model.parameters的grad中 。
最后调用优化器的step方法(step的具体实现可参考torch源码中optim/sgd.py中的step函数),它使用model.parameters中的梯度grad和设置的学习率、动量等参数计算出model.parameters的新data值 , 形如:weight = weight - learning_rate * gradient 。
可以说,最后几步都是针对model.parameters模型参数的修改 。整个过程可以通过跟踪model.parameters的data和grad的内容变化来分析 。方法如下:
for p in model.parameters(): print(p.data, p.grad)
也可以在程序中加入以下代码,用于跟踪后向传播的过程:
f = loss.grad_fn while True: print(f) if len(f.next_functions) == 0: break f = f.next_functions[0][0]
3.预测和做图
本例中用70%数据作为训练集,用所有数据作为测试集,因此,用全部数据重新计算了x,y值;使用eval函数将模型转换为测试模式(有一些层在训练模型和预测模型时有差别);将数据代入模型预测,并转换成numpy格式作图显示 。
x = torch.unsqueeze(torch.tensor(np.array(df['x']), dtype=torch.float32), dim=1) y = torch.unsqueeze(torch.tensor(np.array(df['y']), dtype=torch.float32), dim=1) model.eval() #将模型变为测试模式 predict = model(Variable(x)) # 预测 predict = predict.data.numpy() # 转换成numpy格式 plt.plot(x.numpy(), y.numpy(), 'y') plt.plot(x.numpy(), predict) plt.show()
程序运行结果如下图所示,可以看到模型用一条直线拟合曲线,在前70%的训练数据中表现更好 。
多特征拟合
直线拟合的原理是y=kx b,求斜率k和截距b 。其中的x是数据产生的时间 , 从数据表的索引号转换求得,y是乘客量 。还可以使用另一些方法进一步拟合曲线 。如:
方法一曲线拟合:从图像数据可以看出,乘客数据走势更拟合一条微微上翘的曲线,设y是x的多项式函数,可使用多项式拟合:y=ax3 bx2 cx d 。
方法二多特征拟合:代入更多条件,比如利用年份、月份作为参数代入
多项式函数Python的介绍就聊到这里吧 , 感谢你花时间阅读本站内容,更多关于、多项式函数Python的信息别忘了在本站进行查找喔 。

    推荐阅读