逻辑回归---梯度下降法

前言:

线性关系主要解决一类事物的特点,而逻辑回归注重于解决分类问题,试图寻找多种事物的边界所在,因此掌握逻辑回归是十分必要的!

正文:

#老朋友
import matplotlib.pyplot as plt
import numpy as np
#做模型评估的,正确率,召回率等
from sklearn.metrics import classification_report
#数据是否需要标准化,可以做也可以不做
from sklearn import preprocessing
#False代表不做,True代表做
#做标准化会使数据变得更加准确更加平滑,推荐做
scale = True
#载入数据
data = np.genfromtxt("LR-testSet.csv",delimiter = ",")
#切分数据,从第1列到最后一列但不包括最后一列
x_data = data[:,:-1]
#最后一列
y_data = data[:,-1]
#定义画图函数
def plot():
    x0 = []
    x1 = []
    y0 = []
    y1 = []
    #切分不同类别的数据
    #有多少数据,循环多少次
    for i in range(len(x_data)):
        #如果数据属于y=0这个类别
        if y_data[i] == 0:
            #把每行第一个数据送给x0
            x0.append(x_data[i,0])
            #把每行第二个数据送给y0
            y0.append(x_data[i,1])
        #如果这个数据属于y=1这个类别
        else:
            #把每行第一个数据送给x0
            x1.append(x_data[i,0])
            #把每行第二个数据送给y0
            y1.append(x_data[i,1])
    #开始画图
    #把属于0的点画成点
    scatter0 = plt.scatter(x0,y0,c = 'b',marker = 'o')
    #把属于1的点画成叉
    scatter1 = plt.scatter(x1,y1,c = 'r',marker = 'x')
    #画图例
    #handles表示你要画图例的数据,labels是图例的名称,loc=‘best’表示自动适配
    plt.legend(handles=[scatter0,scatter1],labels=['label0','label1'],loc='best')
plot()
plt.show()

执行效果如下:
在这里插入图片描述

#数据处理,添加偏置项
x_data = data[:,:-1]
#这里注意要给y_data增加维度,让他也变成二维数据来适配函数mat
y_data = data[:,-1,np.newaxis]

print(np.mat(x_data).shape)
print(np.mat(y_data).shape)
#给样本添加偏置项
#concatenate函数可以改变axis的值来进行数据拼接
#axis的值为0时,不改变列数,将数据向下拼接
#axis的值为1时,不改变行数,将数据向右拼接
X_data = np.concatenate((np.ones((100,1)),x_data),axis=1)
print(X_data.shape)

打印出来的data格式如下:
在这里插入图片描述

#预测函数
def sigmoid(x):
    return 1.0/(1+np.exp(-x))
 
#代价函数
def cost(xMat,yMat,ws):
    #函数multiply是按位相乘
    left = np.multiply(yMat,np.log(sigmoid(xMat*ws)))
    right = np.multiply(1-yMat,np.log(1-sigmoid(xMat*ws)))
    #返回公式
    return np.sum(left + right) / -(len(xMat))
    
 def gradAscent(xArr,yArr):
    if scale == True:
        xArr = preprocessing.scale(xArr)
    #将数据变成矩阵形式
    xMat = np.mat(xArr)
    yMat = np.mat(yArr)
    #定义学习率
    lr = 0.001
    #定义循环次数
    epochs = 10000
    #将代价函数的值定义在一个列表
    costList = []
    #计算数据的行列数
    #行代表数据个数,列代表权值个数
    m,n = np.shape(xMat)
    #初始化权值
    ws = np.mat(np.ones((n,1)))
    
    for i in range(epochs+1):
        #xMat和weights矩阵相乘
        h = sigmoid(xMat*ws)
        #计算误差
        #给xMat的矩阵进行转置,才能进行正常的矩阵乘法
        #h-yMat的格式是100*1,xMat.T的矩阵的格式是3*100
        ws_grad = xMat.T*(h-yMat)/m
        #更新ws的值
        ws = ws-lr*ws_grad
        #循环每进行50次,就将更新好的代价函数值代入
        if i%50 == 0:
            costList.append(cost(xMat,yMat,ws))
    return ws,costList
#训练模型,得到权值和cost值的变换
#注意这里的X_data是大写字母
ws,costList = gradAscent(X_data,y_data)
print(ws)

训练后的权值如下:
在这里插入图片描述

#不进行数据标准化时
if scale == False:
    #画图决策边界
    plot()
    x_test = [[-4],[3]]
    y_test = (-ws[0]-x_test*ws[1])/ws[2]
    plt.plot(x_test,y_test,'k')
    plt.show()
#画图 loss值的变化
#定义图像范围
x = np.linspace(0,10000,201)
#给图像起名贴标签
plt.plot(x,costList,c = 'r')
plt.title('Train')
plt.xlabel('epochs')
plt.ylabel('Cost')
plt.show()

图片展示如下:
在这里插入图片描述

#预测
def predict(x_data,ws):
    if scale == True:
        x_data = preprocessing.scale(x_data)
    xMat = np.mat(x_data)
    ws = np.mat(ws)
    return [1 if x>=0.5 else 0 for x in sigmoid(xMat*ws)]
predictions = predict(X_data,ws)
#classification_report计算准确率,召回率
print(classification_report(y_data,predictions))

三种率运算如下:
在这里插入图片描述

总结:

可以看出工作量很高,检查很频繁,容易报错,尤其要求对参数格式的转化,期待sklearn库能使工作变得轻松愉悦!

posted @ 2020-02-25 09:50  超级无敌57  阅读(444)  评论(0编辑  收藏  举报