机器学习算法 之逻辑回归以及python实现

相关文章目录:python

  1. 机器学习 之线性回归
  2. 机器学习 之逻辑回归及python实现
  3. 机器学习项目实战 交易数据异常检测
  4. 机器学习之 决策树(Decision Tree)
  5. 机器学习之 决策树(Decision Tree)python实现
  6. 机器学习之 PCA(主成分分析)
  7. 机器学习之 特征工程 下面分为两个部分:
  8. 逻辑回归的相关原理说明
  9. 经过python代码来实现一个梯度降低求解逻辑回归过程

逻辑回归(Logistic Regression)

首先须要说明,逻辑回归属于分类算法。分类问题和回归问题的区别在于,分类问题的输出是离散的,如(0,1,2,...)而回归问题的输出是连续的。算法

咱们将要用来描述这个分类问题的标记以下:数据结构

m 表明训练集中实例的数量app

n 表明特征的数量dom

x^{(i)} 表示第i个训练实例,是特征矩阵的第i行,是一个向量机器学习

x_j^{(i)} 表示特征矩阵中第i行的第j个特征,也就是第i个训练实例的第j个特征函数

y 表明目标变量,也就是输出变量post

(x,y) 表明训练集中的一个实例学习

(x^{(i)},y^{(i)}) 表明第i个观察实例测试

h 表明学习算法的函数,或者假设(hypothesis)

假设函数

逻辑回归是在线性回归的基础上,转化而来的。它是用来解决经典的二分类问题

首先说明下,什么是二分类问题

咱们将输出结果y可能属于的两个类分别称为负向类(negative class)和正向类(positive class),则输出结果y属于0,1 ,其中 0 表示负向类,1 表示正向类。

咱们将线性回归的输出记为:

z = \theta^TX

咱们知道,线性回归的输出结果是实数域中连续的,要想解决二分类问题,这时,咱们引入Sigmoid函数, 对应公式为:

g(z) = \frac{1}{1+e^{-z}}

对应图像如上图,可见,自变量取值为任意实数,值域为[0,1]

通过sigmoid函数,就将任意的输入映射到了[0,1]区间内,咱们在线性回归中能够获得一个预测值,再将该值进映射到Sigmoid函数中,这样就完成了由值到几率的转换,这就是逻辑回归中的分类任务

因此,咱们逻辑回归的假设函数为:

h_{\theta}(x) = g(\theta^TX) = \frac{1}{1+e^{-\theta^TX}}

逻辑回归的假设函数h_{\theta}(x)即为对应y=1的几率值,即咱们能够用下式表示:

P(y=1 \, |\,x;\theta) = h_{\theta}(x)
P(y=0\, |\,x;\theta) =1 - h_{\theta}(x)

通常状况下,咱们断定 当h_{\theta}(x) >=0.5时,预测y=1,当h_{\theta}(x) < 0.5时,预测y=0

目标函数

将上述几率进行整合,咱们得出:

P(y\,|\,x;\theta) = (h_{\theta}(x))^y(1-h_{\theta}(x))^{1-y}

其中,y属于0,1 因为每一个样本最后得出的几率值都是独立的,因此,对于全部样原本说,咱们能够获得对应似然函数为:

L(\theta) = \prod_{i=1}^{m} P(y^{(i)}\,|\,x^{(i)};\theta) =\prod_{i=1}^{m} (h_{\theta}(x^{(i)}))^{y^{(i)}}(1-h_{\theta}(x^{(i)}))^{1-y^{(i)}}

最终,咱们的目标就是求解最大似然函数,也就是让全部样本数据最终求得是正向类或者负向类的几率越大越好。

为了计算方便,首先,咱们对上述似然函数取对数,得

这个时候,咱们是求的最大值,为了转换为梯度降低任务,因此咱们引入J(\theta) = -\frac{1}{m}l(\theta)

最终,咱们的目标函数为:

J(\theta) = -\frac{1}{m}\sum_ {i=1}^{m} [y^{(i)}log(h_{\theta}(x^{(i)}))+(1-y^{(i)})log(1-h_{\theta}(x^{(i)}))]

gradient descent(梯度降低)

对代价函数求偏导,得:

\frac{\partial J(\theta)}{\partial \theta_j} = {\frac{1}{m}} \sum_ {i=1}^{m}(h_{\theta}(x^{(i)})-y^{(i)})x_j^{(i)}

向量化后,得:

\frac{\partial J(\theta)}{\partial \theta} = \frac{1}{m}X^T(Sigmoid(\theta X)-y)

决策边界

在逻辑回归中,咱们预测:

h_{\theta}(x) >=0.5时,预测y=1,当h_{\theta}(x) < 0.5时,预测y=0

即: 当\theta^TX >= 0时,预测y=1,当\theta^TX < 0时,预测y=1

因此,决策边界为:

\theta^TX = 0

梯度降低求解逻辑回归问题

下面,经过逻辑回归模型,来实现一个预测某个学生是否会被大学录取的问题。假设你是一个大学系的管理员,你想根据两次考试的结果来决定每一个申请人的录取机会,如今你拥有以前申请学生的能够用于训练逻辑回归的训练样本集。对于每个训练样本,你有他们两次测试的评分和最后是被录取的结果。为了完成这个预测任务,咱们准备构建一个能够基于两次测试评分来评估录取可能性的分类模型。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import classification_report#这个包是评价报告
复制代码

首先,让咱们获取下数据,看下数据结构

#exam1,exam2表明两次测试评分,也就是特征值x1,y1,admitted为录取结果,也就是y
data = pd.read_csv('ex2data1.txt',names=['exam1','exam2','admitted'])
data.head()  #打印前五行,看看
复制代码
exam1 exam2 admitted
0 34.623660 78.024693 0
1 30.286711 43.894998 0
2 35.847409 72.902198 0
3 60.182599 86.308552 1
4 79.032736 75.344376 1

一般状况下,进行相关数据可视化,能够帮咱们更好的分析数据

# 数据可视化
sns.lmplot('exam1','exam2', hue='admitted', data=data, size=6,fit_reg=False,scatter_kws={"s":50})
plt.show()
复制代码

数据初始化

包括分离出特征值和输出变量,进行特征缩放以及theat向量的初始化等操做

#进行归一化处理,也就是特征缩放(注意,这块只是针对特征,也就是X)
def normalize_feature(df):
    data_explame = df.iloc[:,:-1]
    data_x = data_explame.apply(lambda column: (column - column.mean())/column.std())
    data = pd.concat([data_x,df.iloc[:,-1]], axis=1)
    return data

#插入x0列并转换为ndarray
def insert_x0_and_asmatrix(data):
    ones = pd.DataFrame({'ones': np.ones(len(data))}) #生成一个m行1列的dataFrame
    data = pd.concat([ones,data], axis=1)  #根据列,合并数据
    return data.as_matrix()    #转化为ndarray进行返回

#刷新数据
def shuffleData(data):
    np.random.shuffle(data)
    return data

#读取特征
def get_X(data):
    return data[:,:-1]

#读取输出变量
def get_Y(data):
    return data[:,-1]


复制代码
data = normalize_feature(data)
data.head()  #打印下特征缩放后的数据看看
复制代码
exam1 exam2 admitted
0 -1.594216 0.635141 0
1 -1.817101 -1.201489 0
2 -1.531325 0.359483 0
3 -0.280687 1.080923 1
4 0.688062 0.490905 1
orig_data = insert_x0_and_asmatrix(data)  #加入x0列
orig_data[0:5]
复制代码
array([[ 1.        , -1.59421626,  0.63514139,  0.        ],
       [ 1.        , -1.81710142, -1.20148852,  0.        ],
       [ 1.        , -1.53132516,  0.35948329,  0.        ],
       [ 1.        , -0.28068724,  1.08092281,  1.        ],
       [ 1.        ,  0.68806193,  0.49090485,  1.        ]])
复制代码
shuffleData(orig_data)  #打乱样本次序
orig_data[0:5]
复制代码
array([[ 1.        ,  0.96558389, -1.22094762,  1.        ],
       [ 1.        ,  0.14514418,  1.04248696,  1.        ],
       [ 1.        ,  0.74754551, -1.15162347,  1.        ],
       [ 1.        , -0.5222529 , -1.64944586,  0.        ],
       [ 1.        ,  0.08608101,  0.01976857,  1.        ]])
复制代码
X = get_X(orig_data)
y = get_Y(orig_data)
theta = np.zeros(3)
X.shape,y.shape,theta
复制代码
((100, 3), (100,), array([0., 0., 0.]))
复制代码

sigmoid函数

g(z) = \frac{1}{1+e^{-z}}
def sigmoid(z):
    return 1/(1+np.exp(-z))
复制代码

咱们来看下sigmoid函数的函数图像

#看下sigmoid函数的函数图像
numbers = np.arange(-10,10,step=0.1)
plt.plot(numbers, sigmoid(numbers),'r')
plt.show()
复制代码

计算代价函数

J(\theta) = -\frac{1}{m}\sum_ {i=1}^{m} [y^{(i)}log(h_{\theta}(x^{(i)}))+(1-y^{(i)})log(1-h_{\theta}(x^{(i)}))]
#计算代价
def cost(theta, X, y):
    return -np.mean(y * np.log(sigmoid(X @ theta)) 
                    + (1-y) * np.log(1-sigmoid(X @ theta)))
复制代码

来,咱们看下初始状态下,代价值是多少

cost(theta, X, y)
复制代码
0.6931471805599453
复制代码

计算梯度

\frac{\partial J(\theta)}{\partial \theta_j} = {\frac{1}{m}} \sum_ {i=1}^{m}(h_{\theta}(x^{(i)})-y^{(i)})x_j^{(i)}

向量化后,得:

\frac{\partial J(\theta)}{\partial \theta} = \frac{1}{m}X^T(Sigmoid(X\theta )-y)
#计算梯度
def gradient(theta, X, y):
    return 1/len(X) * X.T @ (sigmoid(X @ theta) - y)
复制代码

决策边界

\theta^TX = 0
def decision_fun(x,theta):
    coef = -(theta/theta[2])
    print(coef)
    return coef[0] + coef[1]*x

def draw_decision_fun(theta):
    x = np.arange(-2,2,step = 0.01)
    y = decision_fun(x,theta)
    sns.lmplot('exam1','exam2', hue='admitted', data=data, size=6,fit_reg=False,scatter_kws={"s":25})
    plt.plot(x,y)
    plt.xlim(-2,2)
    plt.ylim(-2,2)
    plt.title('Decision Boundary')
    plt.show()
复制代码

在进行梯度降低算法时,咱们有三种不一样的中止策略

  1. 直接设置迭代次数,次数到了中止迭代
  2. 设置一个代价函数降低的阈值,若是本次和上一次迭代完后的代价函数的差值 若是小于这个阈值,则中止迭代
  3. 设置梯度的阈值,若是某次迭代后,梯度小于阈值,则中止迭代
STOP_ITER = 0  #设置迭代次数
STOP_COST = 1  #设置目标函数降低的阈值
STOP_GRAD = 2  #设置梯度的阈值

def stopCriterion(type, value, threshold):
    #设定三种不一样的中止策略
    if type == STOP_ITER:        return value > threshold
    elif type == STOP_COST:      return abs(value[-1]-value[-2]) < threshold
    elif type == STOP_GRAD:      return np.linalg.norm(value) < threshold
复制代码
#绘制代价函数图像
def drwcosts(costs):
    fig, ax = plt.subplots(figsize=(12,4))
    ax.plot(np.arange(len(costs)), costs, 'r')
    ax.set_xlabel('Iterations')
    ax.set_ylabel('Cost')
复制代码

下面来实现梯度降低算法

import time
def descent(data, theta, batchSize, stopType, thresh, alpha):
    init_time = time.time()
    i = 0; #迭代次数
    k = 0; #batch
    X = get_X(data)  
    y = get_Y(data)
    grad = gradient(theta,X,y)  #计算梯度
    costs = [cost(theta, X, y)]   #计算代价值
    
    
    while True:
        #根据不一样的梯度降低算法(批量,随机,小批量),先计算梯度
        grad = gradient(theta, X[k:k+batchSize],y[k:k+batchSize])
        k = k+batchSize
        if k>= data.shape[0]:
            k = 0
            shuffleData(data)   #从新打乱数据
            X = get_X(data)
            y = get_Y(data)
        theta = theta - alpha * grad  #更新theta
        costs.append(cost(theta, X, y)) #保存本次迭代后的目标值
        i += 1  #迭代次数加1
        
        #根据不一样的中止策略,传入不一样的value,来判断迭代是否结束
        if stopType == STOP_ITER: 
            value = i
        elif stopType == STOP_COST:
            value = costs
        elif stopType == STOP_GRAD:
            value = grad
         
        if stopCriterion(stopType, value, thresh):  #若是知足中止策略,则中止迭代
            break
    print("theta:",theta)
    print("迭代次数:",i-1)
    print("最后求得的收敛的目标值:",costs[-1])
    print("最后的梯度:",grad)
    print("所用时间:",time.time() - init_time)
    return theta, i-1, costs, grad, time.time() - init_time
         
            
复制代码

不一样的中止策略

首先看下,当直接设置迭代次数为5000,学习率为0.0001时,对应模型状况

theat, iter, costs, grad, durtime = descent(orig_data, theta, orig_data.shape[0], STOP_ITER, thresh=5000, alpha=0.0001)
drwcosts(costs)
复制代码
theta: [0.04702107 0.13181832 0.11768083]
迭代次数: 5000
最后求得的收敛的目标值: 0.6262088600901743
最后的梯度: [-0.08832936 -0.24808112 -0.22154761]
所用时间: 0.8178122043609619
复制代码

看上面的图像,迭代5000次后,模型远远没到收敛的程度,说明目前尚未近似找到最优解,须要继续增长迭代次数

让咱们将迭代次数,加到30000次看看

heat, iter, costs, grad, durtime = descent(orig_data, theta, orig_data.shape[0], STOP_ITER, thresh=30000, alpha=0.0001)
drwcosts(costs)
复制代码
theta: [0.21656628 0.60953923 0.54481303]
迭代次数: 30000
最后求得的收敛的目标值: 0.44649953741239545
最后的梯度: [-0.05269534 -0.14810478 -0.1325817 ]
所用时间: 4.967716455459595
复制代码

能够看到,相对于上次,此次明显效果稍好点,单是目标函数仍是没能很好的收敛,你能够继续增长迭代次数,或者适当增长学习率,进行尝试看看。

下面,咱们来换种中止策略,采用 设置目标函数降低的阈值 这种中止策略看看

设置阈值为0.000001,学习率为0.001

heat, iter, costs, grad, durtime = descent(orig_data, theta, orig_data.shape[0], STOP_COST, thresh=0.000001, alpha=0.001)
drwcosts(costs)
复制代码
theta: [0.88388452 2.24688547 2.04464801]
迭代次数: 36738
最后求得的收敛的目标值: 0.23470607174751176
最后的梯度: [-0.01016408 -0.02172708 -0.02060574]
所用时间: 6.014917373657227
复制代码

能够看到基本已经收敛。用时6秒钟左右

下面,再来看下 设置梯度的阈值 这种中止策略下训练出的模型

设置梯度阈值为0.01,学习率为0.001

heat, iter, costs, grad, durtime = descent(orig_data, theta, orig_data.shape[0], STOP_GRAD, thresh=0.01, alpha=0.001)
drwcosts(costs)
复制代码
theta: [1.31220652 3.14902915 2.90906189]
迭代次数: 112802
最后求得的收敛的目标值: 0.20918126836321715
最后的梯度: [-0.00323388 -0.00681177 -0.00656816]
所用时间: 19.595609664916992
复制代码

能够看到,此次效果最好,代价函数基本已经收敛,最后的目标值为:0.20918126836321718 迭代了112802次,耗时20秒左右

对比不一样的梯度降低方法

上面,咱们都用的是批量梯度降低,下面,咱们来尝试下随机梯度降低。 中止策略采设置梯度阈值, 阈值为0.01,学习率为0.001

heat, iter, costs, grad, durtime = descent(orig_data, theta, 1,  STOP_GRAD, thresh=0.01, alpha=0.001)
drwcosts(costs)
复制代码
theta: [0.67632327 1.78493605 1.61049596]
迭代次数: 20239
最后求得的收敛的目标值: 0.2623021373549509
最后的梯度: [-0.00449379 -0.00741967 -0.00495884]
所用时间: 1.0222656726837158
复制代码

对比上面的批量梯度降低,能够发现,最后模型效果没批量梯度降低好,可是所用时间明显下降了。

可是,须要注意,采用随机梯度降低,并非每次都能收敛,有时若是样本数据不是很好,可能会出现目标函数没法收敛的状况!

因此,咱们更经常使用批量梯度降低,下面看下

heat, iter, costs, grad, durtime = descent(orig_data, theta, 64,  STOP_GRAD, thresh=0.01, alpha=0.001)
drwcosts(costs)
复制代码
theta: [0.90249119 2.28523187 2.08373685]
迭代次数: 38617
最后求得的收敛的目标值: 0.2329190821129908
最后的梯度: [-0.00311558 -0.00452799 -0.00279034]
所用时间: 4.404224395751953
复制代码

咱们能够看到,批量梯度降低所训练出的模型,效果和所用时间,在上述两种降低算法之间。

用训练集预测和验证

def predict(X,theta):   #预测
    prob = sigmoid(X @ theta)
    return (prob >= 0.5).astype(int)
复制代码
y_predict = predict(X, theat)  #获得训练集数据对应的预测结果
print(classification_report(y, y_predict))
#precision:精确度
#recall:召回率
#f1-score: f1值
复制代码
precision    recall  f1-score   support

        0.0       0.88      0.88      0.88        40
        1.0       0.92      0.92      0.92        60

avg / total       0.90      0.90      0.90       100
复制代码

欢迎关注个人我的公众号 AI计算机视觉工坊,本公众号不按期推送机器学习,深度学习,计算机视觉等相关文章,欢迎你们和我一块儿学习,交流。

相关文章
相关标签/搜索