- 线性回归
假设现有一些二维数据点,我们用一条线(直线或者曲线)对这些点进行拟合,这个拟合的过程就称作回归。如果用直线拟合,就是线性回归。
在多维空间下线性回归的公式为:
z = w0*x0 w1*x1 w2*x2 ··· wn*xn。其中w0~wn为回归系数,
x0~ xn为各坐标值。
用矩阵的写法则为:
- Logistic 函数
Logistic函数是一类函数的集合,其定义为:
其中,x0为x值的中点,L为函数曲线的最大值,k为函数曲线的曲率
- Sigmoid 函数
Sigmoid函数是一个在生物学中常见的S型函数,也称为S型生长曲线。它可以将实数域映射到(0,1),并且单调递增。其函数由下列公式定义:
其导数为:
可以看出,Sigmoid 函数是Logistic函数的一个特例。
Sigmoid函数常用做神经网络的激活函数。它也可以用于Logistic回归分类。我们在每一个特征上乘以一个回归系数然后求和:
再将结果代入Sigmoid函数中,h =S(z), 进而得到一个范围在0~1之间的数值。假如我们的分类问题的结果只有两个类别,则可以将大于等于0.5的归入1类,小于0.5即被归入0类(即z >0 归入1类,z<0 归入0类)。
确定了分类器的函数形式之后,现在的问题变成了:最优的回归系数(矩阵W)是多少?
- 梯度下降算法求最优回归系数
本例的数据集保存在文本文件中:
首先导入数据集,注意,代码里额外添加了一个常数特征x0=1,和w0乘得到截距w0。
代码语言:javascript复制from numpy import *
def loadDataSet():
dataMat = []; labelMat = []
fr = open('testSet.txt')
for line in fr.readlines():
lineArr = line.strip().split()
##添加一个常数特征x0=1,和w0乘得到截距,z = w0 w1*x1 w2*x2
dataMat.append([1.0, float(lineArr[0]), float(lineArr[1])])#
labelMat.append(int(lineArr[2]))
return dataMat,labelMat
定义Sigmoid函数:
代码语言:javascript复制def sigmoid(inX):
return 1.0/(1 exp(-inX))
再用梯度下降算法求权重系数:
代码语言:javascript复制def gradDescend(dataMatIn, classLabels):
dataMatrix = mat(dataMatIn) #mx3 #转换成100x3矩阵(3个特征,含常数特征)
labelMat = mat(classLabels).transpose() #转换成mx1矩阵
m,n = shape(dataMatrix) #m=100, n=
alpha = 0.001 #步长
maxCycles = 500 #最大迭代步数
weights = ones((n,1))#初始化权重可以全部设置为1
for k in range(maxCycles): #heavy on matrix operations
h = sigmoid(dataMatrix*weights) #matrix mult, h shape is m x1
error = h - labelMat #误差,shape mx1
#梯度下降算法的变种
weights -= alpha * dataMatrix.transpose() *error#matrix mult ( 3xm x mx1 -> 3x1)
#print("error = ", error)
return weights # 3x1
求得权重weights(w0,w1, w2 =weights)之后,根据判别临界条件: w0*x0 w1* x1 w2*x2 = 0 ,
即 w0 w1*X w2*Y =0 可得到分类所用直线的方程为:
Y = -(w0 w1*X)/ w2
最后用matplotlab 把数据点和分类的边界线画出来。
可以看到,错判的点数很少。当然,这和数据集的数据点分布有关。只有当数据集基本线性可分时,用本例的线性回归分类算法才能得到较好的效果。
代码语言:javascript复制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:# label =0
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', label ="class 1")
ax.scatter(xcord2, ycord2, s=30, c='green',label ="class 0")
#画出分类所用的线
x = arange(-4.0, 4.0, 0.1)
w0, w1, w2 = weights
y = (0 - w0 - w1*x) / w2
#x= x.reshape(1,-1)
ax.plot(x, y,label ="判别线")
plt.xlabel('X1'); plt.ylabel('X2');
ax.legend()
plt.title("梯度下降算法 Logistic回归 示例")
plt.show()
dataArr, labelMat = loadDataSet()
weights = gradDescend(dataArr, labelMat)
print(weights)
plotBestFit(weights)