logistic回归-(sklearn)参数含义及实现(3)机器学习实战

        经过前两篇的介绍,相信对logistic回归分类已经有一些了解了,下面我们用书上的例子,使用之前的代码和sklearn的库函数解决,看看效果怎么样。


示例:从疝气疾病预测病马的死亡率

1.书中代码实现

这里先导入两个上篇文章的函数,分别是sigmoid函数和随机梯度上升法求最优权数的函数。

def sigmoid(inX):#sigmoid函数
	return 1.0/(1+exp(-inX))
def stocGradAscent1(dataMatrix,classLabels,numIter =150):#改进随机梯度上升算法
	m,n = shape(dataMatrix)#提取数据维度
	weights = ones(n)
	for j in range(numIter):    
		dataIndex = list(range(m))
		for i in range(m):#重复R次变为逐点迭代
			alpha = 4/(1.0+j+i) + 0.01#随着迭代次数上升,步长逐渐变短
			randIndex = int(random.uniform(0,len(dataIndex)))
			h = sigmoid(sum(dataMatrix[randIndex]*weights))#计算预测分类
			error = classLabels[randIndex] - h
			weights = weights + alpha * error * dataMatrix[randIndex]#迭代器
			del(dataIndex[randIndex])
	return weights#返回迭代权数

接下来是本例新增的函数,函数是classifyVector函数,通过stocGradAscent1计算好的权值weights,与输入的向量inX进行运算求和,最后用sigmoid函数二值化,从而得到预测概率,根据概率判断类别。

def classifyVector(inX,weights):
	prob = sigmoid(sum(inX*weights))#计算sigmoid函数值
	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]))#提取训练集标签
	trainWights = stocGradAscent1(array(trainingSet),trainingLabels,500)#500次迭代求出weights
	error_conut = 0;numTestVec = 0.0
	for line in frTest.readlines():
		numTestVec += 1#测试数加1
		currLine = line.strip().split('\t')
		lineArr = []
		for i in range(21):
			lineArr.append(float(currLine[i]))
		if int(classifyVector(array(lineArr),trainWights)) != int(currLine[21]):#计算分类错误数
			error_conut += 1
	errorRate = (float(error_conut)/numTestVec)#计算错误率
	print("the error rate of this test is :%f" %errorRate)
	return errorRate

由于所给数据已经分别给出了训练数据和测试数据,而且stocGradAscent1在拟合参数时也进行了随机化处理,所以这里我们就不使用交叉验证,而是直接根据训练集进行建模,测试集进行测试模型,通过500次迭代求出最优拟合参数,,然后用训练集进行测试,让我们看一下测试的准确率。

the error rate of this test is :0.402985 

为了排除偶然性,再看一下运行多次函数的平均准确率:

def multiTest():
	numTests = 10;errorSum = 0.0
	for k in range(numTests):
		errorSum += colicTest()#计算多次试验的总正确率
	print("after %d iterations the average error rate is : %f" %(numTests,errorSum/float(numTests)))
multiTest()
after 10 iterations the average error rate is : 0.376119

这里37.6%的错误率不是太理想,不过考虑到我们的数据存在30%的缺失,所以整体而言,分类效果还算凑乎,也可以通过调整迭代次数和步长,减小分类错误率。


2.sklearn实现

接下来看一下Sklearn库中的LogisticRegression函数:

码代码之前,先看一下LogisticRegression函数(点击打开链接)的完全体和一些参数信息:

LogisticRegression(penalty='l2'dual=Falsetol=0.0001C=1.0fit_intercept=Trueintercept_scaling=1class_weight=Nonerandom_state=Nonesolver='liblinear'max_iter=100multi_class='ovr'verbose=0warm_start=Falsen_jobs=1)

penalty惩罚项,str类型,可选参数为l1和l2,默认为l2。用于指定惩罚中使用的标准。 'newton-cg','sag'和'lbfgs'求解者只支持l2个惩罚。

tol:float,默认值:1e-4,容许停止标准,即我们说的要迭代停止所需达到的精度要求。

fit_intercept:bool,默认值:True,指定是否应将常数(又称偏差或截距)添加到决策函数中,相当于是否加入截距项b。

class_weight:用于标示分类模型中各种类型的权重,可以是一个字典或者’balanced’字符串,默认为None,也就是不考虑权重,在出现样本不平衡时,可以考虑调整class_weight系数去调整,防止算法对训练样本多的类别偏倚,具体实现方法可以参考西瓜书3.6节类别不平衡问题。

最后最关键的就是solver参数,这决定我们采用什么算法求解拟合最优参数w。

solver : {‘newton-cg’, ‘lbfgs’, ‘liblinear’, ‘sag’, ‘saga’},优化拟合参数算法选择,默认为liblinear。

liblinear:使用坐标轴下降法(西瓜书408.B5)来迭代优化损失函数。

sag:即随机平均梯度下降,类似于我们的stocGradAscent1函数,思想是常用的一阶优化方法,是求解无约束优化问题最经典,最简单的方法之一。

saga线性收敛的随机优化算法。

newton-cg:牛顿法,sag方法使用一阶导数,而牛顿法采用了二阶泰勒展开,这样缩减了迭代轮数,但是 需要计算Hsssian矩阵的逆,所以计算复杂度较高。

lbfgs:拟牛顿法,考虑到牛顿法的Hessian矩阵求逆太过复杂,尤其在高维问题中几乎不可行,想到了用较低的代价寻找Hessian矩阵的近似逆矩阵,便有了拟牛顿法。

#提取训练集
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]))#提取训练集标签
#提取测试集
testingSet = [];testingLabels = []
for line in frTest.readlines():
	
	currLine = line.strip().split('\t')
	lineArr = []
	for i in range(21):
		lineArr.append(float(currLine[i]))
	testingSet.append(lineArr)#提取训练集
	testingLabels.append(float(currLine[21]))#提取训练集标签

from sklearn.linear_model import LogisticRegression

logistic_classifiy = LogisticRegression(penalty ='l2',dual = False,tol = 0.0001,C = 1.0,fit_intercept = True,
										intercept_scaling = 1,class_weight = None,random_state = None,
										solver ='liblinear',max_iter = 100, multi_class ='ovr',verbose = 0,
										warm_start = False,n_jobs = 1)
logistic_classifiy.fit(trainingSet,trainingLabels)
y_pre = logistic_classifiy.predict(testingSet)
errorcount = 0
for i in range(len(y_pre)):
	if y_pre[i] != testingLabels[i]:
		errorcount+=1
print('errorcount = ',errorcount/int(len(y_pre)))

这里我们采用solver = 'liblinear'对上例中的数据进行建模和准确率估计。

errorcount =  0.26865671641791045

相比于之前的算法,LogisticRegression的准确率相对较高,一会我们将solver中的几种算法都尝试一遍,看一下不同算法的不同的准确率。

之前的文章谈到,logistic回归不仅仅分类,还能得到分类的相对概率,所以我们调用函数,看一下LogisticRegression是如何通过概率分类:

print(logistic_classifiy.predict_proba(testingSet))#类别概率
[[ 0.1750072   0.8249928 ]
 [ 0.08800041  0.91199959]
 [ 0.36293821  0.63706179]
 [ 0.37016082  0.62983918]
 [ 0.46481403  0.53518597]
 [ 0.09886075  0.90113925]

由于行数比较多,这里只截取前几列进行了解,第一行为[ 0.1750072   0.8249928 ],意味着类别为0的概率是0.1750072,类别为1的概率是0.8249928,所以针对第一个训练样本,我们判定类别为1,以此类推,大家可以通过predict函数去验证第一个测试集的预测类别是不是1。


3.五种优化算法的正确率对比

logistic_classifiy = LogisticRegression(penalty ='l2',dual = False,tol = 0.0001,C = 1.0,fit_intercept = True,
										intercept_scaling = 1,class_weight = None,random_state = None,
										solver ='liblinear',max_iter = 100, multi_class ='ovr',verbose = 0,
										warm_start = False,n_jobs = 1)

通过修改solver的参数,即可实现几种不同的优化算法,这里就不重复上代码了,让我们看一下几种算法的准确率表现如何。

errorcount by newton-cg is  0.2835820895522388
errorcount by lbfgs is  0.26865671641791045
errorcount by liblinear is  0.26865671641791045
errorcount by sag is  0.22388059701492538
errorcount by saga is  0.22388059701492538

sga系列即随机梯度下降优化法表现最好,错误率为22.4%左右,相较于之前的40%已经有了很大的提升,而其他几种方法都在26%-28%左右,虽然不及sag,但也较之前有了很大的提升,今后遇到类似问题大家可以多调参从而找到最佳的优化算法,更好的解决分类问题。


总结:

logistic回归的大概内容就是这些了,相比于之前的分类算法,logistic略显复杂,但也很容易理解,在了解了分类原理后,可以通过sklearn快速实现不同的优化算法,解决手头的分类问题。人生苦短,你学python,革命路漫漫,大家一起加油!







猜你喜欢

转载自blog.csdn.net/bit_666/article/details/79787504