摘要:
Logistic回归也称为对率线性回归,需要涉及到最优化算法。此回归应用十分广泛,对于回归的预测也是概率的值,既属于回归模型也属于分类模型。
Logistic回归的基本过程
收集数据
准备数据:由于需要距离的计算所以需要为数值同时需要格式化
分析数据:任意方法
训练算法:找到最佳回归系数
测试算法
使用算法:根据输入转换成对应的结构化数据
而如何进行最优系数的求解就需要用到梯度上升等算法
Logistic以及Sigmoid函数分类
我们需要的函数是这样的,接受所有输入然后预测出类别,我们采用数学上的sigmoid函数 g(z) = 1/(1+exp(-z))
当x等于0的时候这个函数的值是0.5,当大于0.5的时候被分为类型1,小于0,5的时候被分为类型0
那么确定了分类标准就需要确定最优化的分类系数
回归系数的确定最优化方法
梯度下降的方法: z= w0x0+w1x1+w2x2+----2n
算法的训练:
此处是基于梯度上升来获得最佳参数的。伪代码如下:每个回归系数初始化1
重复R次:
计算数据集的梯度
使用alpha*gradient更新回归系数的向量
返回回归系数
def loadDataSet(): dataMat = [];labelMat=[] fr = open('testSet.txt') for line in fr.readlines(): lineArr = line.strip().split() 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 sigmoid(inX): return 1.0/(1+exp(-inX)) def compute_grad(theta,xMat,yMat): # h = sigmoid(xMat*theta) # delta = yMat-h # m = shape(xMat)[0] # #若是batch_gradient_descent # grad = (-1.0)*delta.T*xMat # return grad.flatten() m = shape(yMat)[0] h = sigmoid(xMat.dot(theta.reshape(-1, 1))) grad = (1.0) * xMat.T.dot(h - yMat) return (grad.flatten())
#自定义梯度下降 def batch_gradient(J,X,maxIter=500,alpha=0.001): X = mat(X) m = shape(X)[1] theta = ones((m,1)) Jmin,grad = J(theta) for k in range(maxIter): theta = theta - alpha*grad.T Jmin,grad = J(theta) #Jmin = J(theta)#返回梯度下降后的最小值 return theta
测试如下结果:dataArr,labelMat = logRegres.loadDataSet() logRegres.gradAscent(dataArr,labelMat)得到答案是:
[[ 4.12414349]
[ 0.48007329]
[-0.6168482 ]]需要注意的是这里的更新是同步更新并不是异步更新,同时采用梯度上升是由于这里是求的是极大似然估计的值
分析数据:画出决策边界
如何对已经划分出的不同类别数据的分割线呢。
目标是画出如下的图:
绘制程序如下:
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='green') x = arange(-3.0,3.0,0.1) y = (-weights[0]-weights[1]*x)/weights[2] #这里 0 = w0x0 + w1x1 + w2x2 ax.plot(x,y) plt.xlabel('X1');plt.ylabel('X2') plt.show()
训练算法:随机梯度上升
同步的梯度上升算法,每次计算回归系数的时候需要遍历整个数据集合,但是如果有很多个特征,那么计算复杂度会相当的高,改进的方法是一次只用一个回归样本点继续进行更新,该方法是随机梯度上升算法,是一种“在线学习”算法与一次处理所有数据不同,那是一种“批处理算法”
随机梯度上升算法:
对数据集的每个样本点
计算梯度
使用alpha*gradient更新回归系数
返回回归系数
def stoGradAscent0(dataMatrix,classLabels): m,n = shape(dataMatrix) alpha = 0.01 weights = ones(n) for i in range(m): h = sigmoid(dataMatrix[i]*weights) error = classLabels[i] - h weights = weights + alpha*error*dataMatrix[i] return weights
注意和一般梯度下降算法中h ,error区别,这里这两个均是数值而不是向量
测试以及绘制后发现错分了1/3的样本由于一般的梯度上升算法根据迭代次数的来得到更优的划分,所以我们可以改进让该算法迭代200次
但是会出现的问题就是在极值点附近的波动,所以我们可以修改alpha的值,减少波动,同时可以随机选择样本增加多样性减少周期性的波动
增加了分类的效率避免了周期性的波动
def random_gradient(X,y,maxIter=500,alpha=0.001): Xmat = mat(X) ymat = mat(y).transpose() n, m = Xmat.shape theta = mat(ones(m)) for j in range(maxIter): dataIndex = range(m) for i in range(m): alpha = 4/(1.0+j+i) + 0.01 #alpha每次调整越后面越小 randIndex = int(random.uniform(0,n)) #均匀分布随机取其中一个数值 h = sigmoid(Xmat[randIndex]*theta.T) delta = h - ymat[randIndex] theta = theta - alpha*delta*Xmat[randIndex] return theta.T
得到了相当不错的效果
p = LogRegression.predict(theta,dataArr) Pmat = mat(labelArr).transpose() print 'Train Accuracy: %f'% float(mean(p== Pmat)*100)
定义一个预测函数
def predict(theta,X,threshold=0.5): X = mat(X) p = X*theta>0 return p.astype('int')
Train Accuracy: 96.000000
从疝气病预测病马的死亡率
我们直接解析这个例子的数据。有368样本和28个特征。而这数据集是包含了这个得了这个病的一些指标,有些指标比较主观,而有的难以测量,例如疼痛等级。
数据预处理
数据缺失值是这个数据集的主要问题,如果因为某一维特征的确实丢掉所有特征是十分不值当的.所以需要一些方法处理缺失值。数据挖掘中有许多处理手段。特征均值填补
特殊值填补,忽略缺失值样本呢,使用相似样本均值填补,使用机器学习算法预测.
此处我们采用特殊值来代替,为什么可以用0来代替呢。引入如果为0的话weights*X对结果的预测没有倾向性。因为sigmoid(0) = 0.5。但是如果是类别标签缺失那么就没有办法用特殊值代替了。我们处理后的样本为test.txt和train.txt
测试算法
def colicTest(): frTrain = open('horseColicTraining.txt') frTest = open('horseColicTest.txt') trainingSet=[] trainingLabels=[] for line in frTrain.readlines(): curLine = line.strip().split('\t') curArr = [] for i in range(len(curLine)-1): curArr.append(float(curLine[i])) trainingSet.append(curArr) trainingLabels.append(float(curLine[-1])) weights = random_gradient(trainingSet,trainingLabels,maxIter=1000) #predict(weights,trainingSet,trainingLabels) testSet=[] testLabels=[] for line in frTest.readlines(): curLine = line.strip().split('\t') curArr = [] for i in range(len(curLine)-1): curArr.append(float(curLine[i])) testSet.append(curArr) testLabels.append(float(curLine[-1])) predict(weights,testSet,testLabels)
可以用交叉验证来算一下这个平均错误率35%Train Accuracy: 74.626866