一、部分说明
----------------------------------------------------------------
1、本文代码是《机器学习实战》这本书的例程。点击下载《机器学习实战》及原书中的源代码;
2、运行环境为:window10+python3.2+各种python机器学习库。
安装可参考:点击打开链接
3、本文注重代码的实现过程,其基本知识请参考《机器学习实战》和一些知名博客。
4、本人属于初学者,有些注释部分可能不对,还请指正。
5、(1)、本代码从原来的python2.x改为python3.x;
(2)、加入详细的注释,方便理解;
(3)、还有加入自己想要实现的一些功能。
----------------------------------------------------------------
二、重点回顾
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、数据点的二分类2、病马的死亡率预测
为了预测的稳定性,多次重复实验取平均,发现误码率为0,效果真的是很好。
注:本人菜鸟一枚,如有不对的地方还请指正,同时欢迎一起交流学习。