Logistic 回归 代码详解 python3.7

import numpy
def loadDataSet():#打开文本并且逐行读取
    dataMat=[]
    labelMat=[]
    fr=open('testSet.txt')#打开txt文本
    for line in fr.readlines():
        #以空格,换行制表符等分割=隔字符
        lineArr=line.strip().split()#。strip(rm)删除s字符串中开头、结尾处,位于rm删除序列的字符,当rm为空时,当rm为空时,默认删除空白符
        #split()方法通过指定分隔符对字符串进行切片,如果参数num 有指定值,则仅分隔 num 个子字符串,
        # split()默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。
        dataMat.append([1.0,float(lineArr[0]),float(lineArr[1])])#X0设置为1,X1和X2从文件中获得
        labelMat.append(int(lineArr[2]))
    return dataMat,labelMat
def sigmoid(inX):#定义sigmoid函数
    return 1.0/(1+numpy.exp(-inX))
def gradAscent(dataMatIn,classLabels):#定义梯度上升函数
    dataMatrix=numpy.mat(dataMatIn)#转化为NumPy矩阵类型,100行3列
    labelMat=numpy.mat(classLabels).transpose() #转化为NumPy矩阵类型并转置,100行1列
    m,n=numpy.shape(dataMatrix)#获得行数、列数
    alpha=0.001#设置步长
    maxCycles=500 #迭代步数
    weights=numpy.ones((n,1))#权系数初始化,3行1列
    for k in range(maxCycles):#迭代步数
        h=sigmoid(dataMatrix*weights)#得到100行1列,并输入到sigmoid函数中
        error=(labelMat-h)#得到误差
        weights=weights+alpha*dataMatrix.transpose()*error#更新权重系数
    return weights
def plotBestFit(weights):
    import matplotlib.pyplot as plt
    dataMat,labelMat=loadDataSet()#得到数据
    dataArr=numpy.array(dataMat)#把数据变为矩阵
    n=numpy.shape(dataArr)[0]#得到矩阵的行数
    xcord1=[]#定义空的列表
    ycord1=[]
    xcord2=[]
    ycord2=[]
    for i in range(n):
        if int(labelMat[i])==1:#判断那一行数据的标签为1
            xcord1.append(dataArr[i,1]);ycord1.append(dataArr[i,2])#如果为1,把为1的元素的第一个数当做横坐标,第二个数当做纵坐标存起来
        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=numpy.arange(-3.0,3.0,0.1)#坐标轴设置
    y=(-weights[0]-weights[1]*x)/weights[2] #此处x是X1,y是X2, 0=W0*X0+W1*X1+W2*X2  X0=1
    #x,y相当于这个数据的两个特征X1,X2,我们要根据这两个特征来判断这个点属于那一类ax+by+c=0相当于一条分割线,通过之前的训练,
    # 我们已经确定了a,b,c的参数值,然后画出这个分割曲线,即把X2当做y
    ax.plot(x, y)
    plt.xlabel('X1')
    plt.ylabel('X2')
    plt.show()

作图:

import logRegres
import numpy
dataArr,labelMat=logRegres.loadDataSet()
a=logRegres.gradAscent(dataArr,labelMat)
logRegres.plotBestFit(a.getA())#get是把矩阵转化为数组的形式,要不然维度不匹配

得到下图:

def stocGradAscent0(dataMatrix,classLabels):
    m,n=numpy.shape(dataMatrix)#获得数据的行列数
    alpha=0.01
    weights=numpy.ones(n)#初始化权重矩阵
    for i in range(m):
        h=sigmoid(numpy.sum(dataMatrix[i]*weights))#h为一个数值
        error=classLabels[i]-h#为一个数
        weights=weights+alpha*error*dataMatrix[i] #每次对一个样本进行处理,更新权值
    return weights

这是修改过后的程序,具体的错误有红色标记的地方,作者的意思是随机选择dataIndex=[0 1 2 3 4 5]中的一个数,假设选取的是2,我们读取的是dataMatrix[2]这个数据,那么下次迭代时应该不要选取dataMatrix[2]。即从[0 1 3 4 5]中选择,假设我们再次选的下标还是2,那么我们选取的数据依然是dataMatrix[2]这个数据,根本起不到使用不重复的数据的目的,我们其实应该选择的数据是dataMatrix[dataIndex[2]],才能保证数据不重复使用。
需要指出来的是,“随机梯度上升”中的“随机”,意思并不是指每次一定要随机选取一条样本来更新weights。它的实际意思是用近似方法来改善标准梯度下降的时间复杂度,具体的做法是每次选取一条样本(而非所有样本)来近似地计算梯度、更新weights。
上面这段话参考:https://blog.csdn.net/charlielincy/article/details/71082147
def stocGradAscent1(dataMatrix,classLabels,numIter=150):
    m,n=numpy.shape(dataMatrix)#获得数据的行列数
    weights=numpy.ones(n)#初始化权重矩阵
    for j in range(numIter):
        dataIndex=list(range(m))
        for i in range(m):
            alpha=4/(1.0+j+i)+0.01#动态更新alpha,保证每次迭代减小步长,加快收敛速度,吴恩达的机器学习里面讲过这个
            randIndex=int(numpy.random.uniform(0,len(dataIndex)))#随机生成一个样本数据进行训练权值
            h=sigmoid(numpy.sum(dataMatrix[dataIndex[randIndex]]*weights))#h为一个数值
            error=classLabels[dataIndex[randIndex]]-h#为一个数
            weights=weights+alpha*error*dataMatrix[dataIndex[randIndex]] #每次对一个样本进行处理,更新权值
            del(dataIndex[randIndex])#删除选过的随机样本
    return  weights

 

迭代次数为500时

今天写代码需要生成一个整数构成的list,于是很自然地想到range函数。可以当我将生成的内容传入一个需要list参数的函数中,奇怪的事情发生了,竟然提示传入的不是一个list。于是上网寻求解决方法,并进行验证。原来在python3中range的实现变了,并不是返回一个list类型,而是返回一迭代对象。

print(type(range(1,4)))
# 输出:<class 'range'>
print(range(1,4))
# 输出:range(1, 4)
a = list(range(1,4))
print(type(a))
#输出:<class 'list'>
for i in range(1,4):
    print(i)
#输出:1 2 3
  •  

Explain

可以看到range()函数返回的是一个range对象。不过可以使用list()函数将其转换成list对象。range是一个可迭代的对象,可以使用for循环迭代输出。 
貌似这样的设计很反人类,但是设计者这样设计,一定是为了某些特殊的原因。这种设计其实为了节省内存,官网有英文的说明。下面是一位网友给出的翻译。 
在很多种情况下,range()函数返回的对象的行为都很像一个列表,但是它确实不是一个列表,它只是在迭代的情况下返回指定索引的值,但是它并不会在内存中真正产生一个列表对象,这样也是为了节约内存空间。

我们称这种对象是可迭代的,或者是可迭代对象,还有一种对象叫迭代器,它们需要从一个可迭代对象中连续获取指定索引的值,一直到索引结束。list()函数就是这样一个迭代器,它可以把range()函数返回的对象变成一个列表。

Summary

range() 函数返回的是一个可迭代对象(类型是对象),而不是列表类型, 所以打印的时候不会打印列表。 
list() 函数是对象迭代器,把对象转为一个列表。返回的变量类型为列表。

参考:https://blog.csdn.net/liuweiyuxiang/article/details/78461779

len的作用对象是没有range 的,所以要把range对象变为list对象

1:作用:返回字符串、列表、字典、元组等长度

2:语法:len(str)

3:参数: 
str:要计算的字符串、列表、字典、元组等

4:返回值:字符串、列表、字典、元组等元素的长度

预测病马的死亡率:

def classifyVector(inX,weights):
    '''        最终的分类函数,根据回归系数和特征向量来计算 Sigmoid 的值,大于0.5函数返回1,否则返回0
        Args:
            inX -- 特征向量,features
            weights -- 根据梯度下降/随机梯度下降 计算得到的回归系数
        Returns:
            如果 prob 计算大于 0.5 函数返回 1
            否则返回 0
        '''
    prob=sigmoid(sum(inX*weights))
    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')#把当前行的空白符号删除,并且以制表符'\t'分割单词
        #制表符(也叫制表位)的功能是在不使用表格的情况下在垂直方向按列对齐文本。
        # 比较常见的应用包括名单、简单列表等。也可以应用于制作页眉页脚等同一行有几个对齐位置的行。
        lineArr=[]
        for i in range(21):#数据集共有21个特征
            lineArr.append(float(currLine[i]))
        trainingSet.append(lineArr)
        trainingLabels.append(float(currLine[21]))#第22个是标签
    trainWeights=stocGradAscent1(numpy.array(trainingSet),trainingLabels,500)#得到训练好的权重
    #使用array函数创建时,参数必须是由方括号括起来的列表,而不能使用多个数值作为参数调用array
    errorCount=0;numTestVec=0.0#初始化参数
    for line in frTest.readlines():#循环测试集每一行
        numTestVec+=1.0#统计测试集的数据
        currLine=line.strip().split('\t')#划分每行的数据
        lineArr=[]
        for i in range(21):#循环每个特征值
            lineArr.append(float(currLine[i]))#形成一个数据列表向量
        if int(classifyVector(numpy.array(lineArr),trainWeights))!=int(currLine[21]):
            errorCount+=1
    errorRate=(float(errorCount)/numTestVec)
    print("the error rate of this test is: %f" %errorRate)
    return errorRate
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)))
#python中除法,分子分母只要有一个是float类型,那么他的值也是float类型。
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值