- “最小二乘法”的核心就是保证所有数据偏差的平方和最小。(“平方”的在古时侯的称谓为“二乘”)
收集了网上的一个数据,实验最小二乘并用python实现
1 2 3 4 5 6 7 8 9 10
长度(m) 208 152 113 227 137 238 178 104 191 130
宽度(m) 21.6 15.5 10.4 31.0 13.0 32.4 19.0 10.4 19.0 11.8首先选取两个点(208,21.6)(152, 15.5)就可以得到两个方程:
152*k+b=15.5
208*k+b=21.6
解方程组为: k=0.10892857 ,b=-1.05714286
代码实现:
import matplotlib.pyplot as plt
from numpy import *
import numpy as np
from scipy.optimize import leastsq # 引入最小二乘函数
def getData(file):
X = []
Y = []
fileData = open(file)
for data in fileData.readlines():
datalist = data.strip().split(' ')
X.append(float(datalist[0]))
Y.append(float(datalist[1]))
fileData.close()
return X, Y
def squreSolve(A, B):
result = linalg.solve(A, B.T)
return result
path = 'square_data.txt'
X,Y=getData(path)
plt.scatter(X, Y, marker='o', color='red')
# the equation is:
# 152*a+b=15.5
# 328*a+b=32.4
A = mat([[208, 1], [152, 1]])
B = mat([21.6, 15.5])
result = squreSolve(A, B)
resultist = result.tolist()
X=linspace(0,300,300)
Y=resultist[0]*X+resultist[1]
plt.plot(X,Y,color='orange', label="test line", linewidth=2)
plt.legend() #使label显示出来
plt.show()
其中,红色点为原始数据,黄色的直线为画出的直线。
最小二乘法
好了,新的问题来了,这样的k,b是不是最优解呢? 从图可以看出根据两个点计算出来的拟合直线不是很好,不是最优解。 a,b满足什么条件才是最好的?答案是:保证所有数据偏差的平方和最小。
假设所有数据的平方和为M,则
我们现在要做的就是求使得M最小的a和b。请注意这个方程中,我们已知yi和xi
那其实这个方程就是一个以(a,b)为自变量,M为因变量的二元函数。
通过对M来求偏导数,我们得到一个方程组:
=0
=0
求解方程组:,
接着上面的程序代码实现:
#自定义求最下二乘的系数
def leastsqSelf(x,y):
xy=sum(x*y)
xx=sum(x*x)
x_y=sum(x)*sum(y)
x_x=sum(x)*sum(x)
m = len(x)
a=(xy-x_y/m)/(xx-x_x/m)
b=(sum(y)-a*sum(x))/m
return a,b
x=np.array(X)
y=np.array(Y)
a,b=leastsqSelf(x,y)
print "a=", a, '\n', "b=", b
print a,b
x = linspace(0, 300, 3000)
y = a * x + b
plt.plot(x, y, color='b', label="self line", linewidth=2) # 画拟合直线
plt.legend()
plt.show()
图中self line为利用最小二乘法拟合的直线。
在python中最小二乘的使用
# # 求这些数据的最优ab
##需要拟合的函数func以及误差
def func(p, x):
k, b = p
return k * x + b
def error(p, x, y, s):
print s
return func(p, x) - y
# Test,将第一个中求出的a,b作为初始值
p = [resultist[0][0], resultist[1][0]]
# 主函数从此开始最小二乘#
s = "Test the number of iteration"
X, Y = getData(path)
x=np.array(X)
y=np.array(Y)
k,b=p
Para = leastsq(error, p, args=(x, y, s))
k, b = Para[0]
print "k=", k, '\n', "b=", b
x = linspace(0, 300, 3000)
y = k * x + b
plt.plot(x, y, color='red', label="Fitting line", linewidth=2) # 画拟合直线
plt.legend()
plt.show()
函数:
leastsq(func, x0, args=(), Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-08, xtol=1.49012e-08, gtol=0.0, maxfev=0, epsfcn=0.0, factor=100, diag=None, warning=True)
为python自带的最小二乘法:
一般我们只要指定前三个参数就可以了。
func 是我们自己定义的一个计算误差的函数,
x0 是计算的初始参数值
args 是指定func的其他参数
下图显示了三条直线,但是最小二乘法和python自带的拟合直线重合了。
正规方程组代码
from numpy import *
import sys
import os
import matplotlib.pyplot as plt
def loadDataSet(fileName):
X = []; Y = []
fr = open(fileName)
for line in fr.readlines():
curLine = line.strip().split(' ')
X.append(float(curLine[0])); Y.append(float(curLine[-1]))
return X,Y
#绘制图形
def plotscatter(Xmat,Ymat,a,b,plt):
fig = plt.figure()
ax = fig.add_subplot(111) # 绘制图形位置
ax.scatter(Xmat,Ymat,c='blue',marker='o') # 绘制散点图
Xmat.sort() # 对Xmat各元素进行排序
yhat = [a*float(xi)+b for xi in Xmat] # 计算预测值
plt.plot(Xmat,yhat,'r') # 绘制回归线
plt.show()
return yhat
# 数据矩阵,分类标签
xArr,yArr = loadDataSet("regdataset.txt")
# 生成X坐标列
m = len(xArr)
Xmat = mat(ones((m,2)))
for i in xrange(m): Xmat[i,1] = xArr[i]
Ymat = mat(yArr).T # 转换为y列
xTx = Xmat.T*Xmat # 矩阵左乘自身的转置
ws = []
if linalg.det(xTx) != 0.0:
# 计算直线的斜率和截距
# 矩阵正规方程组公式:inv(X.T*X)*X.T*Y
ws = xTx.I * (Xmat.T*Ymat)
else:
print "This matrix is singular, cannot do inverse"
sys.exit(0) # 退出程序
print "ws:",ws
yHat = plotscatter(Xmat[:,1],Ymat,ws[1,0],ws[0,0],plt)
# 计算相关系数:
print corrcoef(yHat,Ymat.T)
相关系数是衡量两个特征列之间相关程度的一种方法,相关系数的取值范围是【-1,1】。相关系数的绝对值越大,则表明特征列X与特征列Y相关程度越高。当X与Y线性相关时,相关系数取值为1(正线性相关)或-1(负线性相关)。