【机器学习实战三:Logistic回归之点的二分类和预测病马的死亡率】

一、部分说明

----------------------------------------------------------------

1、本文代码是《机器学习实战》这本书的例程。点击下载《机器学习实战》及原书中的源代码;

2、运行环境为:window10+python3.2+各种python机器学习库

     安装可参考:点击打开链接

3、本文注重代码的实现过程,其基本知识请参考《机器学习实战》和一些知名博客。

4、本人属于初学者,有些注释部分可能不对,还请指正。

5、(1)、本代码从原来的python2.x改为python3.x

      (2)、加入详细的注释,方便理解;

      (3)、还有加入自己想要实现的一些功能。

----------------------------------------------------------------

二、重点回顾

【机器学习实战三:Logistic回归之点的二分类和预测病马的死亡率】_第1张图片

5、处理数据的缺失值

(1)、使用可用特征的均值来填补缺失值;

(2)、使用特殊值来填补缺失值,如-1;

(3)、忽略有缺失值得样本;

(4)、使用相似样本的均值添补缺失值;

(5)、使用另外的机器学习算法预测缺失值;

6、梯度算法的改进

关于梯度算法的改进,如随机的梯度算法,改进的随机梯度算法,可以通过源代码注释查看他们之间的差别,和比较结果了解他们之间的优劣性。

三、源代码

# coding=gbk
'''***********************************************************
  Copyright (C), 2015-2020, cyp Tech. Co., Ltd.
  FileName:           逻辑回归分类器.cpp
  Author:             cyp     
  Version :           v1.0          
  Date:               2015-10-21 晚上21:02
  Description:        利用逻辑回归预测病马的死亡率     
  Function List:      
    1.  loadDataset:       载入数据集及标签
	2.  sigmoid:            运用sigmoid方式将数据预处理
	3.  gradAscent:         梯度上升算法
	4.  randGradAscent:    随机梯度上升算法
	5.  improRandGradAscent:改进随机梯度上升算法
	6.  classifyVector:     运用回归算法分类
	7.  dieOfhorseTest:     回归算法预测病马的死亡率
	8.  mulTests:           多次测试,求的平均病马死亡率
	9.  plotBestFit:        数据点集的分类效果的直观的展示
	10. main:               相当与主函数
***********************************************************'''


'''***********************************************************
需要导入的模块
***********************************************************'''
import random
import math
import numpy as np
from numpy import * 
     
'''***********************************************************
  Function:        loadDataset
  Description:     载入数据,及标签
  Calls:           
  Called By:       test
  Input:           无
  Return:          dataSet:读取的数据集
				   label:数据集对应的标签
************************************************************'''
def loadDataset():
	dataSet = []                        #数据集
	labels = []                         #标签
	cwd = 'C://Users//cyp//Documents//sourcecode'
	cwd =cwd + '//machinelearning//my__code//chapter5//'
	fr = open(cwd+"testSet.txt")
	for line in fr.readlines():
		lineVec = line.strip().split()  #读取每一行,[x1,x2,label]
		#[x0,x1,x2],其中x0表示常数项
		dataSet.append([1.0,float(lineVec[0]),float(lineVec[1])])
		labels.append(float(lineVec[2]))#添加标签
	return dataSet,labels               #返回读取的数据集,及标签
'''***********************************************************
  Fun	ction:        sigmoid
  Description:     将输入的数据映射到0-1
  Calls:           
  Called By:       
  Input:           xVec:向量
  Return:          同输入数组一样大
************************************************************'''
def sigmoid(xVec):#根据输入数据的类型分开处理
		if np.array(xVec).shape == np.array(0).shape:#如果输入为一个数值
			if xVec > 100:    #防止数据计算溢出
				xVec = 100
			if xVec < -100:   #防止数据计算溢出
				xVec = -100
			return 1.0/(1+math.exp(-xVec))
		else:     #数组
			ret = []
			for x in xVec:
				x1 = x
				if x1 > 100:  #防止数据计算溢出
					x1 = 100
				if x1 < -100: #防止数据计算溢出
					x1 = -100
				ret.append(1.0/(1+math.exp(-x1))) 
			return ret 
'''***********************************************************
  Function:        gradAscent
  Description:     运用梯度上身算法求解最佳系数weights
  Calls:           
  Called By:       
  Input:           dataSet:用于训练数据集
				   label:数据集对应的标签
  Return:          weight:求得的最佳系数
************************************************************'''
def gradAscent(dataSet,label):
	dataSet = np.mat(dataSet)      #list转换为array
	label = np.array(label).T      #list转换为array
	label = mat(label)
	m,n = dataSet.shape            #m参与训练数据集数,n表示每组的维度
	alpha = 0.02                   #学习速率
	maxCycles = 1000               #训练的迭代的次数
	weights = np.ones((n,1))       #初始权值都为1
	weights = mat(weights)
	for i in range(maxCycles):     #迭代求weights
		h = sigmoid(dataSet*weights)
		error = label - h          #差
		weights = weights + alpha * (dataSet.T*error.T)#更新权值
	return weights
	#对于这个算法,每次迭代会使用所有数据集,其中h,error都是矢量
'''***********************************************************
  Function:        randGradAscent
  Description:     运用随机梯度上身算法求解最佳系数weights
  Calls:           
  Called By:       
  Input:           dataSet:用于训练数据集
				   label:数据集对应的标签
  Return:          weight:求得的最佳系数
************************************************************'''
def randGradAscent(dataSet,label,numIter=89):
	dataSet = np.array(dataSet)    #list转换为array
	label = np.array(label).T      #list转换为array
	m,n = dataSet.shape            #m参与训练数据集数,n表示每组的维度
	alpha = 0.01                   #学习速率
	weights = np.ones((n,1))       #初始权值都为1
	for j in range(numIter):
		for i in range(m):         #迭代m次,求weights
			h = sigmoid(sum(dataSet[i]*weights))
			error = label[i] - h   #差
			weights = weights + alpha *error*dataSet[i]#更新权值
	return weights
	#对于这个算法,每次迭代只用一组数据,即可更新weights,故又称在线学习算法
	#其中h,error都是数值
'''***********************************************************
  Function:        improRandGradAscent
  Description:     运用改进随机梯度上身算法求解最佳系数weights
  Calls:           
  Called By:       
  Input:           dataSet:用于训练数据集
				   label:数据集对应的标签
  Return:          weight:求得的最佳系数
************************************************************'''
def improRandGradAscent(dataSet,label,numIter=150):
	dataSet = np.array(dataSet)    #list转换为array
	label = np.array(label).T      #list转换为array
	m,n = dataSet.shape            #m参与训练数据集数,n表示每组的维度
	weights = np.ones(n)           #初始权值都为1
	weights = np.array(weights)
	for j in range(numIter): 
		dataIndex = [x for x in range(m)]#0-(numIter-1)
		for i in range(m):          #迭代m次,所有数据参与迭代的次数
			alpha = 4/(1.0+i+j)+0.01#学习速率,周期波动,总体收敛于0.01
			#每次内循环迭代不规律,以免周期振荡
			randIndex = int(random.uniform(0,len(dataIndex)))
			h = sigmoid(sum(dataSet[randIndex]*weights))   
			error = label[randIndex] - h       #差
			weights = weights + alpha *error*dataSet[randIndex]#更新权值
			del(dataIndex[randIndex])#删除已被用数据集
	return weights
	#对于这个算法,每次迭代只用一组数据,即可更新weights,故又称在线学习算法
	#其中h,error都是数值,同时学习速率随着迭代的次数变化而变化和非周期的训练
	#数据有利于数据的收敛
'''***********************************************************
  Function:        classifyVector
  Description:     对数据进行分类
  Calls:           
  Called By:       
  Input:           xVec:要分类的一组数据
			       weights:用于分类的权值
  Return:          分类结果
************************************************************'''
def classifyVector(xVec,weights):
	xVec = np.array(xVec)          #list转换为array
	weights = np.array(weights)    #list转换为array
	prob = sigmoid(sum(xVec*weights))
	if prob > 0.5:
		return 1.0
	else:
		return 0.0
'''***********************************************************
  Function:         dieOfhorseTest
  Description:      对病马的死亡率预测
  Calls:           
  Called By:       
  Input:            无
  Return:           errorRate:分类错误率
************************************************************'''
def dieOfhorseTest():
	cwd = 'C://Users//cyp//Documents//sourcecode'
	cwd =cwd + '//machinelearning//my__code//chapter5//'
	frTrain = open(cwd+"horseColicTraining.txt")#训练数据
	frTest = open(cwd+"horseColicTest.txt")     #测试数据
	trainDataSet = []            #存储训练数据
	trianLabels = []             #存储对应的标签
	for line in frTrain.readlines():
		words = line.strip().split("\t")
		words = [float(word) for word in words]
		trainDataSet.append(words[0:-1])#前n-1个数据是一组数据
		trianLabels.append(words[-1])   #第n个是标签
	#训练求的权值
	weights = randGradAscent(trainDataSet,trianLabels)
	errorCount = 0.0             #测试分类错误的个数
	testCount =0.0               #参与测试的总个数
	for line in frTest.readlines():
		testCount += 1           #测试数加1
		words = line.strip().split("\t")
		words = [float(word) for word in words]
		#分类不正确
		if classifyVector(words[0:-1],weights) != int(words[-1]):
			errorCount += 1      #错误数加1
		errorRate = float(errorCount)/testCount#对应的错误率
		print("the error rate of this test is",errorRate)
		return errorRate
'''***********************************************************
  Function:        multiTest
  Description:     多次分类测试,去平均值
  Calls:           
  Called By:       
  Input:           无  		      
  Return:          无
************************************************************'''
def multiTest():
	mulTests = 10   #重复测试次数
	errorRate = 0.0 
	for i in range(mulTests):
		errorRate += dieOfhorseTest() #总错误率
	#输出总重复次数,平均错误率
	print("after %d interations , the average error rate is:%f\
	"%(mulTests,errorRate/mulTests))
'''***********************************************************
  Function:        plotBestFit
  Description:     画图直观看点分类效果
  Calls:           
  Called By:       
  Input:             
  Return:          无
************************************************************'''
def plotBestFit():
	import matplotlib.pyplot as plt
	dataSet,labels = loadDataset() #导入数据集
	weights = gradAscent(dataSet,labels)#训练数据
	weights = np.array(weights)
	label1X = []  #存放A类数据的x坐标
	label1Y = []  #存放A类数据的x坐标
	label2X = []  #存放B类数据的x坐标
	label2Y = []  #存放B类数据的x坐标
	for i in range(len(dataSet)):
		if int(labels[i]) == 1:#属于A类
			#dataSet[i],由x0,x1,x2组成
			label1X.append(dataSet[i][1])#存储x坐标
			label1Y.append(dataSet[i][2])#存储x坐标
		else:#属于A类
			label2X.append(dataSet[i][1])#存储x坐标
			label2Y.append(dataSet[i][2])#存储x坐标
	fig = plt.figure()
	ax = fig.add_subplot(111)
	#在图上已不同的形式画出来
	ax.scatter(label1X,label1Y,s=30,c='red',marker='s')
	ax.scatter(label2X,label2Y,s=30,c='green')
	X = np.arange(-3.0,3.0,0.1)
	#x0*w0+x1*w1+x2*w2 = 0
	#x2=(-x0*w0-x1*w1)/w2
	#x2及是y
	Y = [(-weights[0]-weights[1]*x1)/weights[2] for x1 in X]	
	ax.plot(X,Y)
	plt.xlabel('X1')     #画出x轴标签
	plt.ylabel('X2')     #画出y轴标签
	plt.show()           #显示图
'''***********************************************************
  Function:        main
  Description:     用于调用plotBestFit,multiTest
  Calls:           
  Called By:       
************************************************************'''
if __name__=="__main__":
	plotBestFit()
	multiTest()

四、实验结果

1、数据点的二分类

   通过图形显示,发现分类效果很好。
【机器学习实战三:Logistic回归之点的二分类和预测病马的死亡率】_第2张图片

2、病马的死亡率预测

 为了预测的稳定性,多次重复实验取平均,发现误码率为0,效果真的是很好。

【机器学习实战三:Logistic回归之点的二分类和预测病马的死亡率】_第3张图片

                               注:本人菜鸟一枚,如有不对的地方还请指正,同时欢迎一起交流学习。

你可能感兴趣的:(机器学习,python,Logistic回归,点的二分类,预测病马的死亡率,机器学习实战)