摘要:
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
从疝气病预测病马的死亡率
数据预处理
数据缺失值是这个数据集的主要问题,如果因为某一维特征的确实丢掉所有特征是十分不值当的.所以需要一些方法处理缺失值。数据挖掘中有许多处理手段。特征均值填补
特殊值填补,忽略缺失值样本呢,使用相似样本均值填补,使用机器学习算法预测.
此处我们采用特殊值来代替,为什么可以用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