机器学习之最小二乘法

  1. “最小二乘法”的核心就是保证所有数据偏差的平方和最小。(“平方”的在古时侯的称谓为“二乘”)
  2. 收集了网上的一个数据,实验最小二乘并用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(负线性相关)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值