本次学习的内容是《机器学习》一书中的线性模型这一章节另外这一章节理论性的东西更多,所以还学习了《Machine Learning in Action》中的Logistic回归,实战了一些简单的例子作为互补参考。
代码以及测试用例:
https://github.com/CallMeSp/MachineLearning.git
先说一个数学符号:
arg min f(x) 是指使得函数 f(x) 取得其最小值的所有自变量 x 的集合。比如,函数 cos(x) 在 ±π、±3π、±5π、……处取得最小值(-1),则 argmin cos(x) = {±π, ±3π, ±5π, …}。
如果函数 f(x) 只在一处取得其最小值,则 argmin f(x) 为单点集.
给定d个属性描述的示例 x=(x1;x2;...;xd) x = ( x 1 ; x 2 ; . . . ; x d ) ,其中xi是x在第i个属性的取值。线性模型试图学得一个通过属性的线性组合来进行预测的函数,即
用向量形式写成:
,其中
w和b学得之后,模型就得以确定。
给定数据集,其中
,yi∈R 。“线性回归”试图学得一个线性模型以尽可能准确的预测实值输出标记。
先考虑一种最简单的情形:输入属性的数目只有一个,线性回归试图学得
使得f(xi)≈yi。
如何确定w和b呢?显然关键是如何衡量f(x)和y之间的差别,而均方误差是回归任务中最常用的性能度量,因此我们可试图让均方误差最小化,即
均方误差有非常好的几何意义,对应了常用的欧几里得距离或简称“欧式距离”。基于均方误差最小化来进行模型求解的方法称为“最小二乘法”。在线性回归中,最小二乘法就是试图找到一条直线,使所有样本到直线上的欧式距离之和最小。
为求解w和b使E=∑ (yi-wxi-b)^2最小化的过程,称为线性回归模型的最小二乘“参数估计”,我们可以将E分别对w和b求偏导。
分别令其为0则可得到w和b的最优解的闭式解
更一般的情形是如本节开头的数据集D,样本由d个属性描述,此时试图学得
这称为多元线性回归。
类似的,可利用最小二乘法来对w和b进行估计,为便于讨论,我们把w和b吸入向量形式w=(w;b),相应的把数据集D表示为一个m*(d+1)大小的矩阵X,其中每一行对应于一个实例,该行前d个元素对应于示例的d个属性值,最后一个元素恒置为1即
再把标记也写成向量形式于是类似的有
,令
,对w求导得
令上式为0可得w最优解的闭式解。
考虑二分任务,其输出标记y∈{0,1},而线性回归模型产生的预测值是实值,所以需要将实值z转换为0/1值。最理想的是单位阶跃函数
但是该函数不连续,所以需要找到一个函数一定程度上近似单位阶跃函数,并且单点课为,对数几率函数(logistic function)正是这样一个常用替代函数:
从而得到:(其对应模型称为对数几率回归,实际是一种分类学习方法)
于是可进一步变化为:
若将y视为样本x作为正例的可能性,则1-y是其反例的可能性,两者的比值称为“几率”,取对数则得到对数几率。
将y视为后验概率p(y=1|x)则可将上式重写为
显然有于是可以通过极大似然法来估计w和b:
logistic回归实战。
from numpy import *
import matplotlib.pyplot as plt
def loadDataSet():
dataMat=[]
labelMat=[]
fr=open('testSet.txt','r')
for line in fr.readlines():
lineArr=line.strip().split()
# 每行前两个值作为x1,x2,另外加一个x0,设为1.0
dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
def sigmoid(inX):
return 1.0/(1+exp(-inX))
def gradAscent(dataMatIn,classLabels):
# 将普通矩阵转化为numpy矩阵数据类型
dataMatrix=mat(dataMatIn)
# 矩阵的转置,转化为列矩阵
labelMat=mat(classLabels).transpose()
m,n=shape(dataMatrix)
alepha=0.001
maxCycles=500
weights=ones((n,1))
for k in range(maxCycles):
h=sigmoid(dataMatrix*weights)
error=(labelMat-h)
weights=weights+alepha*dataMatrix.transpose()*error
return weights
def plotBestFit(weights):
import matplotlib.pyplot as plt
dataMat,labelMat=loadDataSet()
dataArr=array(dataMat)
n = shape(dataArr)[0]
xcord1=[];ycord1=[]
xcord2=[];ycord2=[]
for i in range(n):
if int(labelMat[i])==1:
xcord1.append(dataArr[i,1]);ycord1.append(dataArr[i,2])
else:
xcord2.append(dataArr[i,1]);ycord2.append(dataArr[i,2])
fig=plt.figure()
ax=fig.add_subplot(111)
ax.scatter(xcord1,ycord1,s=30,c='red',marker='s')
ax.scatter(xcord2,ycord2,s=30,c='blue')
x=arange(-3.0,3.0,0.1)
y=(-weights[0]-weights[1]*x)/weights[2]
# to make x and y's shape be same ,transpost y
ax.plot(x,y.transpose())
plt.xlabel('X1');plt.ylabel('X2');
plt.show()
def stocGradAscent0(dataArr,classLabels):
m,n=shape(dataArr)
alpha=0.01
weights=ones(n)
for i in range(m):
h=sigmoid(sum(dataArr[i]*weights))
error=classLabels[i]-h
weights=weights*alpha*error*dataArr[i]
return weights
def stocGradAscent1(dataArr, classLabels, numIter=150):
m,n = shape(dataArr) #返回dataMatrix的大小。m为行数,n为列数。
weights = ones(n) #参数初始化
for j in range(numIter):
dataIndex = list(range(m))
for i in range(m):
alpha = 4/(1.0+j+i)+0.01 #降低alpha的大小,每次减小1/(j+i)。
randIndex = int(random.uniform(0,len(dataIndex))) #随机选取样本
h = sigmoid(sum(dataArr[randIndex]*weights)) #选择随机选取的一个样本,计算h
error = classLabels[randIndex] - h #计算误差
weights = weights + alpha * error * dataArr[randIndex] #更新回归系数
del(dataIndex[randIndex]) #删除已经使用的样本
return weights
def classifyVector(inX,weights):
prob=sigmoid(sum(inX*weights))
if prob>0.5:
return 1.0
else:
return 0.0
def colicTest():
frTrain=open('horseColicTraining.txt')
frTest=open('horseColicTest.txt')
trainingSet=[]
trainingLabels=[]
for line in frTrain.readlines():
currLine=line.strip().split('\t')
lineArr=[]
for i in range(21):
lineArr.append(float(currLine[i]))
trainingSet.append(lineArr)
trainingLabels.append(float(currLine[21]))
trainWeights=stocGradAscent1(array(trainingSet),trainingLabels,500)
errorCount=0
numTestVec=0.0
for line in frTest.readlines():
numTestVec+=1.0
currLine=line.strip().split('\t')
lineArr=[]
for i in range(21):
lineArr.append(float(currLine[i]))
if int(classifyVector(array(lineArr),trainWeights))!=int(currLine[21]):
errorCount+=1
errorRate=float(errorCount)/numTestVec
print('the error count is : %f'%errorRate)
return errorRate
def multiTest():
numTest=10
errorSum=0.0
for i in range(numTest):
errorSum+=colicTest()
print('after %d iterations the average error rate is %f'%(numTest,errorSum/float(numTest)))
if(__name__=='__main__'):
# dataArr,labelMat=loadDataSet()
# weights=stocGradAscent1(array(dataArr),labelMat)
# print(weights)
# plotBestFit(weights)
multiTest()