数据分析师养成之路之python篇(从头学习机器学习之逻辑回归)

Logistic回归:
要实现分类,如二分类,我们需要得到的结果是 0,1,即y(x)=0,或y(x)=1,要如何实现这样的效果呢?
单位阶跃函数可以帮助我们实现!
单位阶跃函数: 自变量大于0时,函数值为1; 自变量小于0时,函数值为0(自变量为0时,函数值不做要求)
这里写图片描述
1.Heaviside step function(海维塞德阶跃函数):
这里写图片描述
如上图,该函数在跳跃点x=0上,函数值由0直接跳跃到1,这个跳跃的过程有时很难处理,于是,sigmoid函数登场了
2. sigmoid函数:
先看它的图像:
这里写图片描述
其一它的输出并不是像heaviside那样只有0,1而是随着x值增大,它趋向于1,随着x值减少,它趋向于0(总之,它的输出是在0~1之间)
其二和heaviside相比,它不是从某个点直接由0跳跃到1,而是有了一个过度.当x=0时,函数值为0.5
它的公式如下:
这里写图片描述
接下来,我们要怎么用sigmoid函数来进行分类呢,
每个特征乘以一个回归系数,然后把所有的结果值相加:
z=w0x0 + w1x1 + w2x2 …. + wnxn
所得到的z作为sigmoid函数的输入,将其带入sigmoid中,进而得到一个范围在0~1间的数值(正如sigmoid图像,分布在0~1之间,其中x=0时,函数值为0.5),这个数值如果大于0.5,则被分入1类,小于0.5,则被分入0类.
问题来了,回归系数怎么确定?(最佳回归系数是多少?)

z=w0x0 + w1x1 + w2x2 …. + wnxn,可以写成z=W^T *X
(这里随便提一下:这里写图片描述,这里的B就是W^T,A就是X,BA=z)
梯度上升法:
这里写图片描述
以上是f(x,y)的梯度,(对x求偏导–沿着x方向移动,对y求偏导–沿着 y方向移动),我们沿着梯度方向走,能找到函数的最大值,逆着梯度方向走,能找到函数的最小值
* 因为我们要求参数Wi,所有即需要对Wi求偏导数(求梯度),若偏导数(梯度)等于0,得到驻点,若该点左右导数符号相反,则该点为极值点,即一个Wi的解,例如我们在线性回归中,y=ax+b,其中,a,b参数即为所求,如何求? RSS=n组(Yi-(aXi+b))^2的和,RSS分别对a,b求偏导(梯度),使梯度=0,即可求出,a,b的值。
* 这里,我们要寻找最优参数,即得到最好的Wi值,我们的Wi值需要不断更新,达到我们的要求后停止。
梯度上升:
参数=参数+步长*梯度
这里写图片描述
(梯度下降:
参数=参数-步长*梯度)

实现梯度上升算法:
(简言之,梯度,就是损失函数对要优化的参数求偏导(梯度))

import pandas as pd
import numpy as np
class1=np.random.randint(0,2,size=10)
data_1=np.random.uniform(-1,1,size=10)
data_2=np.random.uniform(1,20,size=10)

df=pd.DataFrame({'data_1':data_1,'data_2':data_2})

dataMatrix=np.mat(df)
classMat=np.mat(class1).transpose()

M,N=np.shape(dataMatrix)
weights=np.ones((N,1))
alpha=0.01
maxCycle=50

#以下代码主要用于计算梯度,实现参数更新
def sigmoid(intX):
    sig=1/(1+np.exp(-intX))

    return sig
for i in range(maxCycle):
    # 得到y_pre=W*x
    h=sigmoid(dataMatrix*weights)
    # error=(classMat-W*x),这里, alpha * 后面的值是梯度值( 1/2 * error^2 对weights 求偏导(梯度)))
    # 1/2( y_true-y_pre)^2=RSS, 其中y_true=classMat,y_pre=h=W*X, 得到的结果为 X*(classMat-h)
    weights=weights+alpha* dataMatrix.transpose()*(classMat-h)





如上,我们的参数经过了maxCycle次更新
其中

for i in range(maxCycle):
    # 得到y_pre=W*x
    h=sigmoid(dataMatrix*weights)
    weights=weights+alpha* dataMatrix.transpose()*(classMat-h)

这里,我们在更新参数(回归系数)时,每次更新都需要遍历整个数据集,当数据集很大,特征很多的时候,这种方法就不适用了,它的计算复杂度会非常高!
于是,它的改进算法,随机梯度上升出现了!
随机梯度上升:

import pandas as pd
import numpy as np
class1=np.random.randint(0,2,size=10)
data_1=np.random.uniform(-1,1,size=10)
data_2=np.random.uniform(1,20,size=10)

df=pd.DataFrame({'data_1':data_1,'data_2':data_2})

dataMatrix=np.mat(df)
classMat=np.mat(class1).transpose()
M,N=np.shape(dataMatrix)
weights=np.ones((N,1))
alpha=0.01
# 注意这里和梯度上升的区别,迭代M次,每次用一个样本来计算梯度并更新回归系数
for i in range(M):
    h=sigmoid(sum(dataMatrix[i]*weights))
    error=classMat[i]-h
    weights=weights+alpha*dataMatrix[i].transpose()*error

判断优化算法是否可靠,我们需要看它是否收敛,即参数是否达到了稳定值,而不是上下高幅度波动。
而以上优化算法中的Weights值在经过大量的迭代后才能达到稳定,并且存在局部波动的现象。
我们期望算法能避免以上的现象,从而快速收敛到某个值,于是,改进的随机梯度上升算法出现了。
改进随机梯度上升算法:

import pandas as pd
import numpy as np
class1=np.random.randint(0,2,size=10)
data_1=np.random.uniform(-1,1,size=10)
data_2=np.random.uniform(1,20,size=10)

df=pd.DataFrame({'data_1':data_1,'data_2':data_2})
dataMatrix=np.mat(df)
classMat=np.mat(class1).transpose()

 M,N=np.shape(dataMatrix)
 weights=np.ones((N,1))
#这里intNum迭代次数自己定,如150
 for j in range(intNum):
     dataIndex=list(range(M))
     for i in range(M):
         # 步长在每次迭代时都需要调整
         # alpha会随着迭代次数不断减小,但是不会减少到0
         alpha=4/(1+i+j)+0.01
         # 随机选取样本,用该样本求梯度,并更新参数
         randIndex=int(np.random.uniform(0,len(dataIndex)))
         h=sigmoid(sum(dataMatrix[randIndex]*weights))
         error=classMat[randIndex]-h
        weights=weights+alpha*dataMatrix[randIndex].transpose()*error
            # 每次随机所取出 的样本再用过之后删除
         del(dataIndex[randIndex])

改进的算法与原来的比较:
1.alpha值可变,逐渐减少,但不为0
2.用随机抽取样本,来更新参数,并且每次的样本不会重复

用逻辑回归进行分类

import pandas as pd
import numpy as np
class1=np.random.randint(0,2,size=10)
data_1=np.random.uniform(-1,1,size=10)
data_2=np.random.uniform(1,20,size=10)

df=pd.DataFrame({'data_1':data_1,'data_2':data_2})
dataMatrix=np.mat(df)
classMat=np.mat(class1).transpose()
index_test=np.random.permutation(int(len(df)*0.3))
index_train=np.random.permutation(int(len(df)*0.7))
data_test=dataMatrix[index_test]
data_train=dataMatrix[index_train]

class_test=classMat[index_test]
class_train=classMat[index_train]
#改进的随机梯度上升法
def  stocGradAscent1(dataMatrix,classMat,intNum):
    M,N=np.shape(dataMatrix)
    weights=np.ones((N,1))

    for j in range(intNum):
        dataIndex=list(range(M))
        for i in range(M):
            # 步长在每次迭代时都需要调整
            # alpha会随着迭代次数不断减小,但是不会减少到0
            alpha=4/(1+i+j)+0.01
            # 随机选取样本,用该样本求梯度,并更新参数
            randIndex=int(np.random.uniform(0,len(dataIndex)))
            h=sigmoid(sum(dataMatrix[randIndex]*weights))
            error=classMat[randIndex]-h
            weights=weights+alpha*dataMatrix[randIndex].transpose()*error
            # 每次随机所取出 的样本再用过之后删除
            del(dataIndex[randIndex])
    return weights
# 用于分类
def classifyVector(inX, weights):
    prob = sigmoid(sum(inX*weights))
    if prob > 0.5: 
        return 1.0
    else:
        return 0.0
# 判断判错率
def testError(data_train,class_train,data_test,class_test):
    train_weights=stocGradAscent1(data_train,class_train,intNum=15)
    i=0
    errorCount=0
    for test in data_test:
        if classifyVector(test,train_weights)!= int(class_test[i]):
            errorCount += 1
        i+=1
    errorRate = (float(errorCount)/i)
    return errorRate
 # 多次测试
def multiTest():
    numTests = 10; errorSum=0.0
    for k in range(numTests):
        errorSum += testError(data_train,class_train,data_test,class_test)
    print ("after %d iterations the average error rate is: %f" % (numTests, errorSum/float(numTests)))

multiTest()

猜你喜欢

转载自blog.csdn.net/lulujiang1996/article/details/81316537
今日推荐