机器学习逻辑回归算法

逻辑回归概述

逻辑回归是目前就广泛使用较多的一种算法,能够贴合的场景也比较多,主要是他提现了数据建模中很重要的思想:对问题划分层次,并利用非线性变换和线性模型的组合,将未知的复杂问题分解为已知的简单问题

逻辑回归虽然名字中回归,但是他的本质上是一种分类算法,其原理是将样本的特征样本发生的概率联系起来,即,预测的是样本发生的概率是多少但是也由于概率是一个数,所以被称为逻辑回归。

在传统中的线性回归算法中,我们对房间进行预测的结果值是一个函数,fx对应一个y值,y则是我们的预测的房价,也就是直接输出的一个数值。

但是在逻辑回归的算法中,得到的预测值是一个概率,然后在概率的基础上多做进一步的操作,就可以得到风控的结果。比如在某银行使用逻辑回归做风控模型,先设置一个阈值0.5,通过逻辑回归来计算对应的概率,如果他的概率大于0.5则判定为风险,所以这是一个标准的分类问题。

在回归问题上再多做一步,就可以作为分类算法来使用了。逻辑回归只能解决二分类问题,如果是多分类问题,LR本身是不支持的。

逻辑回归的背后逻辑

逻辑回归使用什么样的方式来得到一个事件发生的概率值的呢?分类的背后又是什么呢?
以银行理财产品营销场景为例,对于银行来说,客户只有“买”和“不买”两种行为,但是这个行为实际上是客户在接到营销行为,如电话营销、短信营销之后,经过内心博弈产生的最终结果。

客户为什么会做出“买”或“不买”这样的被分类的行为?如果客户手里有一笔暂时不会动用的闲钱,且他希望能够通过投资行为获利,并且对盈利效果表示认可,则客户会考虑购买理财产品。但是反过来,如果客户没有钱,或者他有其他更好的投资渠道,或者厌恶投资风险,那么客户就不会购买。从经济学的角度来说,购买理财产品这一行为,既能给客户带来正效用,也能给客户带来负效用当客户主观认为正效用大于负效用时,可就是购买行为带来的整体效用大于0时,客户就会购买,反之则不然。

逻辑回归假设数据服从伯努利分布,通过极大似然函数的方法,运用梯度下降来求解参数,来达到将数据二分类的目的。

逻辑回归是一个非线性模型,但是是其背后是以线性回归为理论支撑的。

逻辑回归的使用

python代码的实现

from myAlgorithm.model_selection import train_test_split
from myAlgorithm.LogisticRegression import LogisticRegression

X_train, X_test, y_train, y_test = train_test_split(X, y, seed=666)
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
# 查看训练数据集分类准确度
log_reg.score(X_test, y_test)
"""
输出:1.0
"""

# 查看逻辑回归得到的概率
log_reg.predict_proba(X_test)
"""
输出:
array([ 0.92972035,  0.98664939,  0.14852024,  0.17601199,  0.0369836 ,
        0.0186637 ,  0.04936918,  0.99669244,  0.97993941,  0.74524655,
        0.04473194,  0.00339285,  0.26131273,  0.0369836 ,  0.84192923,
        0.79892262,  0.82890209,  0.32358166,  0.06535323,  0.20735334])
"""

# 得到逻辑回归分类结果
log_reg.predict(X_test)
"""
输出:
array([1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0])
"""

决策边界

所谓决策边界就是能够把样本正确分类的一条边界,主要有线性决策边界(linear decision boundaries)和非线性决策边界(non-linear decision boundaries)。
注意:决策边界是假设函数的属性,由参数决定,而不是由数据集的特征决定。

在这里插入图片描述

多项式思路对非线性决策边界数据进行分类

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(666)
X = np.random.normal(0, 1, size=(200, 2))
y = np.array((X[:,0]**2+X[:,1]**2)<1.5, dtype='int')
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

在这里插入图片描述

from myAlgorithm.LogisticRegression import LogisticRegression

log_reg = LogisticRegression()
log_reg.fit(X, y)
log_reg.score(X, y)

# 绘制决策边界的方法
def plot_decision_boundary(model, axis):
    x0, x1 = np.meshgrid(
        np.linspace(axis[0], axis[1], int((axis[1]-axis[0])*100)).reshape(-1, 1),
        np.linspace(axis[2], axis[3], int((axis[3]-axis[2])*100)).reshape(-1, 1),
    )
    X_new = np.c_[x0.ravel(), x1.ravel()]
    y_predict = model.predict(X_new)
    zz = y_predict.reshape(x0.shape)
    from matplotlib.colors import ListedColormap
    custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9']) 
    plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)

plot_decision_boundary(log_reg, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

在这里插入图片描述

from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

# 为逻辑回归添加多项式项的管道
def PolynomialLogisticRegression(degree):
    return Pipeline([
        ('poly', PolynomialFeatures(degree=degree)),
        ('std_scaler', StandardScaler()),
        ('log_reg', LogisticRegression())
    ])

# 使用管道得到对象
poly_log_reg = PolynomialLogisticRegression(degree=2)
poly_log_reg.fit(X, y)

"""
输出:
Pipeline(steps=[('poly', PolynomialFeatures(degree=2, include_bias=True, interaction_only=False)), ('std_scaler', StandardScaler(copy=True, with_mean=True, with_std=True)), ('log_reg', LogisticRegression())])
"""

poly_log_reg.score(X, y)
"""
输出:
0.94999999999999996
"""
plot_decision_boundary(poly_log_reg, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

在这里插入图片描述
下面我们更改degree参数(多项式拓展的阶数),将其变大(那肯定会过拟合):

poly_log_reg2 = PolynomialLogisticRegression(degree=20)
poly_log_reg2.fit(X, y)
plot_decision_boundary(poly_log_reg2, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

在这里插入图片描述

最终的结果,决策边界的外侧比较奇怪,这就是典型的过拟合。

sklearn中的逻辑回归及正则化

在逻辑回归中添加多项式项,从而得到不规则的决策边界,进而对非线性的数据进行很好的分类。但是众所周知,添加多项式项之后,模型会变变得很复杂,非常容易出现过拟合。因此就需要使用正则化,且sklearn中的逻辑回归,都是使用的正则化。

构建回归数据

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(666)
# 构建服从标准差为0,方差为1的分布,200个样本,有两个特征
X = np.random.normal(0, 1, size=(200, 2))
# 构建输入空间X与标签y的关系:是一个抛物线,通过布尔向量转为int类型
y = np.array((X[:,0]**2+X[:,1])<1.5, dtype='int')
# 随机在样本中挑20个点,强制分类为1(相当于噪音)
for _ in range(20):
    y[np.random.randint(200)] = 1
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

在这里插入图片描述

sklearn中的逻辑回归

from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=666)

log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)

返回的逻辑回归参数

LogisticRegression(C=1.0, class_weight=None, dual=False, fit_intercept=True,
                   intercept_scaling=1, l1_ratio=None, max_iter=100,
                   multi_class='warn', n_jobs=None, penalty='l2',
                   random_state=None, solver='warn', tol=0.0001, verbose=0,
                   warm_start=False)

注意观察,有一个参数penalty的默认参数是l2,这说明sklearn中默认是使用L2正则项的,且超参数C默认1。

log_reg.score(X_train, y_train)
"""
输出:
0.79333333333333333
"""
log_reg.score(X_test, y_test)
"""
输出:
0.85999999999999999
"""

我们发现准确不高,这很正常!因为设置的就是非线性的数据,而现在用的还是没加多项式的逻辑回归。
下面可以可视化一下决策边界:

def plot_decision_boundary(model, axis):   
    x0, x1 = np.meshgrid(
        np.linspace(axis[0], axis[1], int((axis[1]-axis[0])*100)).reshape(-1, 1),
        np.linspace(axis[2], axis[3], int((axis[3]-axis[2])*100)).reshape(-1, 1),
    )
    X_new = np.c_[x0.ravel(), x1.ravel()]
    y_predict = model.predict(X_new)
    zz = y_predict.reshape(x0.shape)
    from matplotlib.colors import ListedColormap
    custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
    plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)

plot_decision_boundary(log_reg, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

在这里插入图片描述

多项式逻辑回归

尝试使用多项式项进行逻辑回归。使用pipeline方式组合三个步骤,得到一个使用多项式项的逻辑回归的方法

from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

def PolynomialLogisticRegression(degree):
    return Pipeline([
        ('poly', PolynomialFeatures(degree=degree)),
        ('std_scaler', StandardScaler()),
        ('log_reg', LogisticRegression())
    ])

poly_log_reg = PolynomialLogisticRegression(degree=2)
poly_log_reg.fit(X_train, y_train)

参数结果

Pipeline(memory=None,
         steps=[('poly',
                 PolynomialFeatures(degree=2, include_bias=True,
                                    interaction_only=False, order='C')),
                ('std_scaler',
                 StandardScaler(copy=True, with_mean=True, with_std=True)),
                ('log_reg',
                 LogisticRegression(C=1.0, class_weight=None, dual=False,
                                    fit_intercept=True, intercept_scaling=1,
                                    l1_ratio=None, max_iter=100,
                                    multi_class='warn', n_jobs=None,
                                    penalty='l2', random_state=None,
                                    solver='warn', tol=0.0001, verbose=0,
                                    warm_start=False))],
         verbose=False)

看一下训练结果

poly_log_reg.score(X_train, y_train)
"""
输出:0.91333333333333333
"""
poly_log_reg.score(X_test, y_test)
"""
输出:
0.93999999999999995
"""
plot_decision_boundary(poly_log_reg, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

在这里插入图片描述

尝试过拟合

下面设置一个比较大的阶数

poly_log_reg2 = PolynomialLogisticRegression(degree=20)
poly_log_reg2.fit(X_train, y_train)
poly_log_reg2.score(X_train, y_train)
"""
输出:0.93999999999999995
"""
poly_log_reg2.score(X_test, y_test)
"""
输出:0.93999999999999995
"""
plot_decision_boundary(poly_log_reg2, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

在这里插入图片描述

其实单看结果,还看不出来太多,因为我们的模型设置的很简单。但是看决策边界的话,就知道,这个奇奇怪怪的曲线,一瞅就是过拟合了。
下面就在这个过拟合的基础上,加入模型的正则化。

模型正则化

L2正则

使用参数进行模型正则化,在构建管道时,用参数C去覆盖。同时在生成多项式逻辑回归实例参数时,同样设置阶数为20,然后设置一个比较小的损失函数的权重参数C=0.1,相当于让模型正则化的项起到更大的作用,让分类准确度损失函数起到小一点的作用。

def PolynomialLogisticRegression(degree, C):
    return Pipeline([
        ('poly', PolynomialFeatures(degree=degree)),
        ('std_scaler', StandardScaler()),
        ('log_reg', LogisticRegression(C=C))
    ])

poly_log_reg3 = PolynomialLogisticRegression(degree=20, C=0.1)
poly_log_reg3.fit(X_train, y_train)

poly_log_reg3.score(X_train, y_train)
"""
输出:0.85333333333333339
"""
poly_log_reg3.score(X_test, y_test)
"""
输出:0.92000000000000004
"""
plot_decision_boundary(poly_log_reg3, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

在这里插入图片描述
感觉没有太大的变化

L1正则
def PolynomialLogisticRegression(degree, C, penalty):
    return Pipeline([
        ('poly', PolynomialFeatures(degree=degree)),
        ('std_scaler', StandardScaler()),
        ('log_reg', LogisticRegression(C=C, penalty=penalty))
    ])

poly_log_reg4 = PolynomialLogisticRegression(degree=20, C=0.1, penalty='l1')
poly_log_reg4.fit(X_train, y_train)
poly_log_reg4.score(X_train, y_train)
"""
输出:0.8266666666666667
"""
poly_log_reg4.score(X_test, y_test)
"""
输出:0.9
"""
plot_decision_boundary(poly_log_reg4, axis=[-4, 4, -4, 4])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

在这里插入图片描述
较好的解决了过拟合问题

总结

决策边界是分类中非常重要的一个概念。线性决策边界就是一条直线,而在真实数据,很少是一根直线就能分类的,通常都要加上多项式项,也就是非线性的决策边界。这样才能解决更复杂的问题。
但是多项式项的阶数越大,越容易过拟合。那么就要进行模型的正则化.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值