【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合

前文推荐:
       【Python数据挖掘课程】一.安装Python及爬虫入门介绍
       【Python数据挖掘课程】二.Kmeans聚类数据分析及Anaconda介绍
       【Python数据挖掘课程】三.Kmeans聚类代码实现、作业及优化
       【Python数据挖掘课程】四.决策树DTC数据分析及鸢尾数据集分析
       【Python数据挖掘课程】五.线性回归知识及预测糖尿病实例
       【Python数据挖掘课程】六.Numpy、Pandas和Matplotlib包基础知识
       【Python数据挖掘课程】七.PCA降维操作及subplot子图绘制
       【Python数据挖掘课程】八.关联规则挖掘及Apriori实现购物推荐
       【Python数据挖掘课程】九.回归模型LinearRegression简单分析氧化物数据
       【python数据挖掘课程】十.Pandas、Matplotlib、PCA绘图实用代码补充
       【python数据挖掘课程】十一.Pandas、Matplotlib结合SQL语句可视化分析
       【python数据挖掘课程】十二.Pandas、Matplotlib结合SQL语句对比图分析
       【python数据挖掘课程】十三.WordCloud词云配置过程及词频分析


一. Scipy介绍

        SciPy (pronounced "Sigh Pie") 是一个开源的数学、科学和工程计算包。它是一款方便、易于使用、专为科学和工程设计的Python工具包,包括统计、优化、整合、线性代数模块、傅里叶变换、信号和图像处理、常微分方程求解器等等。
        官方地址:https://www.scipy.org/

【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合

        Scipy常用的模块及功能如下图所示:
        强烈推荐刘神的文章:Scipy高端科学计算 - 刘一痕

【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合

        Scipy优化和拟合采用的是optimize模块,该模块提供了函数最小值(标量或多维)、曲线拟合和寻找等式的根的有用算法。

【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合

        官方介绍:scipy.optimize.curve_fit
        下面将从实例进行详细介绍,包括:
        1.调用 numpy.polyfit() 函数实现一次二次多项式拟合;
        2.Pandas导入数据后,调用Scipy实现次方拟合;
        3.实现np.exp()形式e的次方拟合;
        4.实现三个参数的形式拟合;
        5.最后通过幂率图形分析介绍自己的一些想法和问题。



二. 曲线拟合


1.多项式拟合

        首先通过numpy.arange定义x、y坐标,然后调用polyfit()函数进行3次多项式拟合,最后调用Matplotlib函数进行散点图绘制(x,y)坐标,并绘制预测的曲线。
        完整代码:

[python] view plain copy
  1. #encoding=utf-8    
  2. import numpy as np  
  3. import matplotlib.pyplot as plt  
  4.   
  5. #定义x、y散点坐标  
  6. x = np.arange(1161)  
  7. num = [4.005.205.9006.807.34,  
  8.        8.579.8610.1212.5614.32,  
  9.        15.4216.5018.9219.5820.00]  
  10. y = np.array(num)  
  11.   
  12. #用3次多项式拟合  
  13. f1 = np.polyfit(x, y, 3)  
  14. p1 = np.poly1d(f1)  
  15. print(p1)  
  16.   
  17. #也可使用yvals=np.polyval(f1, x)  
  18. yvals = p1(x)  #拟合y值  
  19.   
  20. #绘图  
  21. plot1 = plt.plot(x, y, 's',label='original values')  
  22. plot2 = plt.plot(x, yvals, 'r',label='polyfit values')  
  23. plt.xlabel('x')  
  24. plt.ylabel('y')  
  25. plt.legend(loc=4#指定legend的位置右下角  
  26. plt.title('polyfitting')  
  27. plt.show()  
  28. plt.savefig('test.png')  
        输出结果如下图所示,包括蓝色的正方形散点和红色的拟合曲线。
        多项式函数为: y=-0.004669 x3 + 0.1392 x2 + 0.04214 x + 4.313

【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合

        补充:给出函数,可以用 Origin 进行绘图的,也比较方便。


2.e的b/x次方拟合

        下面采用Scipy的curve_fit()对上面的数据进行e的b/x次方拟合。数据集如下:

[python] view plain copy
  1. x = np.arange(1161)  
  2. num = [4.005.205.9006.807.34,  
  3.        8.579.8610.1212.5614.32,  
  4.        15.4216.5018.9219.5820.00]  
  5. y = np.array(num)  
        其中,x坐标从1到15,y对应Num数组,比如第一个点(1, 4.00)、最后一个点(15, 20.00)。
        然后调用curve_fit()函数,核心步骤:
        (1) 定义需要拟合的函数类型,如:
            def func(x, a, b):
                return a*np.exp(b/x)
        (2) 调用 popt, pcov = curve_fit(func, x, y) 函数进行拟合,并将拟合系数存储在popt中,a=popt[0]、b=popt[1]进行调用;
        (3) 调用func(x, a, b)函数,其中x表示横轴表,a、b表示对应的参数。
        完整代码如下:

[python] view plain copy
  1. #encoding=utf-8    
  2. import numpy as np  
  3. import matplotlib.pyplot as plt  
  4. from scipy.optimize import curve_fit  
  5.   
  6. #自定义函数 e指数形式  
  7. def func(x, a, b):  
  8.     return a*np.exp(b/x)  
  9.   
  10. #定义x、y散点坐标  
  11. x = np.arange(1161)  
  12. num = [4.005.205.9006.807.34,  
  13.        8.579.8610.1212.5614.32,  
  14.        15.4216.5018.9219.5820.00]  
  15. y = np.array(num)  
  16.   
  17. #非线性最小二乘法拟合  
  18. popt, pcov = curve_fit(func, x, y)  
  19. #获取popt里面是拟合系数  
  20. a = popt[0]   
  21. b = popt[1]  
  22. yvals = func(x,a,b) #拟合y值  
  23. print u'系数a:', a  
  24. print u'系数b:', b  
  25.   
  26. #绘图  
  27. plot1 = plt.plot(x, y, 's',label='original values')  
  28. plot2 = plt.plot(x, yvals, 'r',label='polyfit values')  
  29. plt.xlabel('x')  
  30. plt.ylabel('y')  
  31. plt.legend(loc=4#指定legend的位置右下角  
  32. plt.title('curve_fit')  
  33. plt.show()  
  34. plt.savefig('test2.png')  
        绘制的图形如下所示,拟合效果没有多项式的好。

【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合



3.aX的b次方拟合

        第三种方法是通过Pandas导入数据,因为通常数据都会存储在csv、excel或数据库中,所以这里结合读写数据绘制a*x的b次方形式。
        假设本地存在一个data.csv文件,数据集如下图所示:

【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合

       然后调用Pandas扩展包读取数据,并获取x、y值显示,这段代码如下:
[python] view plain copy
  1. #导入数据及x、y散点坐标  
  2. data = pd.read_csv("data.csv")  
  3. print data  
  4. print(data.shape)      
  5. print(data.head(5)) #显示前5行数据  
  6. x = data['x'#获取x列  
  7. y = data['y'#获取y列  
  8. print x  
  9. print y  
        比如 print y 输出结果:
[python] view plain copy
  1. 0      4.00  
  2. 1      5.20  
  3. 2      5.90  
  4. 3      6.80  
  5. 4      7.34  
  6. 5      8.57  
  7. 6      9.86  
  8. 7     10.12  
  9. 8     12.56  
  10. 9     14.32  
  11. 10    15.42  
  12. 11    16.50  
  13. 12    18.92  
  14. 13    19.58  
  15. 14    20.00  
  16. Name: y, dtype: float64  
        最后完整的拟合代码如下所示:
[python] view plain copy
  1. #encoding=utf-8    
  2. import numpy as np  
  3. import matplotlib.pyplot as plt  
  4. from scipy.optimize import curve_fit  
  5. import pandas as pd    
  6.   
  7. #自定义函数 e指数形式  
  8. def func(x, a, b):  
  9.     return a*pow(x,b)  
  10.   
  11. #导入数据及x、y散点坐标  
  12. data = pd.read_csv("data.csv")  
  13. print data  
  14. print(data.shape)      
  15. print(data.head(5)) #显示前5行数据  
  16. x = data['x']  
  17. y = data['y']  
  18. print x  
  19. print y  
  20.   
  21. #非线性最小二乘法拟合  
  22. popt, pcov = curve_fit(func, x, y)  
  23. #获取popt里面是拟合系数  
  24. a = popt[0]   
  25. b = popt[1]  
  26. yvals = func(x,a,b) #拟合y值  
  27. print u'系数a:', a  
  28. print u'系数b:', b  
  29.   
  30. #绘图  
  31. plot1 = plt.plot(x, y, 's',label='original values')  
  32. plot2 = plt.plot(x, yvals, 'r',label='polyfit values')  
  33. plt.xlabel('x')  
  34. plt.ylabel('y')  
  35. plt.legend(loc=4#指定legend的位置右下角  
  36. plt.title('curve_fit')  
  37. plt.savefig('test3.png')  
  38. plt.show()  
        输出结果如下图所示:
【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合



4.三个参数拟合

        最后介绍官方给出的实例,讲述传递三个参数,通常为 a*e(b/x)+c形式。

[python] view plain copy
  1. import numpy as np  
  2. import matplotlib.pyplot as plt  
  3. from scipy.optimize import curve_fit  
  4.   
  5. def func(x, a, b, c):  
  6.     return a * np.exp(-b * x) + c  
  7.   
  8. # define the data to be fit with some noise  
  9. xdata = np.linspace(0450)  
  10. y = func(xdata, 2.51.30.5)  
  11. y_noise = 0.2 * np.random.normal(size=xdata.size)  
  12. ydata = y + y_noise  
  13. plt.plot(xdata, ydata, 'b-', label='data')  
  14.   
  15. # Fit for the parameters a, b, c of the function `func`  
  16. popt, pcov = curve_fit(func, xdata, ydata)  
  17. plt.plot(xdata, func(xdata, *popt), 'r-', label='fit')  
  18.   
  19. # Constrain the optimization to the region of ``0 < a < 3``, ``0 < b < 2``  
  20. # and ``0 < c < 1``:  
  21. popt, pcov = curve_fit(func, xdata, ydata, bounds=(0, [3.2.1.]))  
  22. plt.plot(xdata, func(xdata, *popt), 'g--', label='fit-with-bounds')  
  23.   
  24. plt.xlabel('x')  
  25. plt.ylabel('y')  
  26. plt.legend()  
  27. plt.show()  
        输出结果如下图所示:
【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合


三. 幂律分布拟合及疑问

        下面是我幂率分布的实验,因为涉及到保密,所以只提出几个问题。
        图1是多项式的拟合结果,基本符合图形趋势。
        图2是幂指数拟合结果,幂指数为-1.18也符合人类的基本活动规律。

【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合 【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合
        问题:
        1.为什么幂律分布拟合的图形不太好,而指数却很好;
        2.计算幂指数及拟合是否只对中间那部分效果好的进行拟合;
        3.e的b/x次方、多项方程、x的b次方哪个效果好?


【python数据挖掘课程】十四.Scipy调用curve_fit实现曲线拟合