python编程导论 豆瓣_python编程导论_第十二课

胡克定律

胡克定律指出弹性与力成正比,用公式表述就是F = -kx。换句话说,弹簧中储存的力F与弹簧被压缩(或拉伸)的距离成线性关系。(负号表示弹簧发力的方向与其位移方向相反。)它不适用于任意大的力,所有弹簧都有一个弹性极限,超过这个极限的话,胡克定律就失效了。

如果在弹簧上悬挂多个重量不断增加的物体,并测量出弹簧每次

拉伸的长度,然后绘制结果,并将结果保存在springData.txt文件中:

Distance (m) Mass (kg)

0.0865 0.1

0.1015 0.15

0.4416 0.9

下面第代码可以从我们保存的文件中读取数据,并绘制距离和质量的数据图。

import pylab, random

def getData(fileName):

dataFile = open(fileName, 'r')

distances = []

masses = []

discardHeader = dataFile.readline()

for line in dataFile:

d, m = line.split()

distances.append(float(d))

masses.append(float(m))

dataFile.close()

return (masses, distances)

def plotData(fileName):

xVals, yVals = getData(fileName)

xVals = pylab.array(xVals)

yVals = pylab.array(yVals)

xVals = xVals*9.81 # convert mass to force (F = mg)

pylab.plot(xVals, yVals, 'bo', label = 'Measured displacements')

pylab.title('Measured Displacement of Spring')

pylab.xlabel('Force (Newtons)')

pylab.ylabel('Distance (meters)')

plotData('springData.txt')

pylab.show()

图中的点并不在一条直线上,这和胡克定律并不相符。如果有一条直线可以表示我们的最佳预测,即表示如果没有测量误差时点应该在哪个位置,那就更好了。要达到这个目的,通常的做法是使用一条直线拟合数据。

使用线性回归进行拟合

不论我们使用何种曲线(包括直线)拟合数据,都需要某种方法确定哪条曲线才是数据的最佳拟合。这意味着我们需要定义一个目标函数,对曲线拟合数据的程度提供一个定量的评价。如果我们定义了目标函数,那么找到最优拟合就可以明确表述为一个最优化问题:找到一条曲线,使目标函数值最小(或最大)。

最常用的目标函数称为最小二乘。令observed和predicted为两个同样长度的向量,observed中是实际测量出来的点, predicted中则是拟合曲线上相应的数据点。那么,目标函数就可以定义为:

PyLab中提供了一个内置函数polyfit,它可以找出最小二乘拟合的近似解。调用以下函数:

pylab.polyfit (observedXVals, observedYVals, n)

可以找出一组n阶多项式的系数,这个多项式就是定义在observedXVals和observedYVals这两个数组中的数据点的最优最小二乘拟合。举例来说,调用以下函数:

pylab.polyfit(observedXVals, observedYVals, 1)

可以找出一条由多项式y = ax + b定义的直线,这里的a是直线的斜率, b是Y轴上的截距,函数会返回一个带有两个浮点数的数组。

ployfit使用的算法称为线性回归。fitData函数扩展了上述plotData函数,添加了一条直线来表示数据的最佳拟合。它使用polyfit找出系数a和b,然后使用这些系数为每个力生成弹簧位移的预测值。

def fitData(fileName):

xVals, yVals = getData(fileName)

xVals = pylab.array(xVals)

yVals = pylab.array(yVals)

xVals = xVals*9.81 # convert mass to force (F = mg)

pylab.plot(xVals, yVals, 'bo', label = 'Measured points')

pylab.title('Measured Displacement of Spring')

pylab.xlabel('Force (Newtons)')

pylab.ylabel('Distance (meters)')

a,b = pylab.polyfit(xVals, yVals, 1) # fit y = ax + b

# use line equation to graph predicted values

estYVals = a*xVals + b

k = 1/a

pylab.plot(xVals, estYVals, label = 'Linear fit, k = '

+ str(round(k, 5)))

pylab.legend(loc = 'best')

fitData('springData.txt')

pylab.show()

调用fitData('springData.txt')会生成下面的图形:

只有很少几个点落在最小二乘拟合的直线上,这个拟合看上去不够好。我们向fitData添加一些代码,试一下三次拟合:

#find cubic fit

fit = pylab.polyfit(forces, distances, 3)

predictedDistances = pylab.polyval(fit, forces)

pylab.plot(forces, predictedDistances, 'k:', label = 'cubic fit')

这段代码会生成下面的图形。三次拟合建立的数据模型看上去要比线性拟合好很多,但真的是这样吗?未必如此。

线性拟合与三次拟合

在技术文献中,我们经常会看到类似的图,其中既有原始数据,也有一条拟合数据的曲线。然而,作者往往会将拟合曲线当作对真实情况的描述,而将原始数据看作实验误差。这是非常危险的一种做法。

理论上x值和y值应该是线性关系,而不是三次关系。但是如果使用三次模型预测悬挂1.5千克物体时弹簧的位移,那么相应的点会在哪里?如图所示。

使用模型进行预测

这时,三次模型表现得就不那么好了。在弹簧上悬挂一个非常重的物体,居然会使弹簧上升得比最初的悬挂位置还高(y值是负数),这简直是天方夜谭。这种情况就是过拟合的典型例子。当模型过于复杂时,经常会出现过拟合,例如,数据量较少而参数特别多的时候。发生过拟合时,拟合模型反映出的是数据中的噪声,而不是数据中有意义的关系。过拟合模型的预测能力通常很弱,就像这个例子中一样。

你可能感兴趣的:(python编程导论,豆瓣)