什么是逻辑回归

逻辑回归虽然名字有回归,但解决的是分类问题。

逻辑回归既可以看做回归算法,也可以看做是分类算法,通常作为分类算法用,只可以解决二分类问题。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

机器学习(6)——逻辑回归 人工智能 第1张

Sigmoid函数:机器学习(6)——逻辑回归 人工智能 第2张

import numpy as np
import matplotlib.pyplot as plt

def sigmoid(t):
    return 1 / (1+np.exp(-t))
    
x=np.linspace(-10,10,500)
y=sigmoid(x)
plt.plot(x,y)
plt.show()

机器学习(6)——逻辑回归 人工智能 第3张

机器学习(6)——逻辑回归 人工智能 第4张

逻辑回归的损失函数

机器学习(6)——逻辑回归 人工智能 第5张

机器学习(6)——逻辑回归 人工智能 第6张

机器学习(6)——逻辑回归 人工智能 第7张

机器学习(6)——逻辑回归 人工智能 第8张

机器学习(6)——逻辑回归 人工智能 第9张

机器学习(6)——逻辑回归 人工智能 第10张

推导过程这里就不赘述了,高等数学基本知识。

机器学习(6)——逻辑回归 人工智能 第11张

机器学习(6)——逻辑回归 人工智能 第12张

向量化:

机器学习(6)——逻辑回归 人工智能 第13张

逻辑回归的向量化梯度:

机器学习(6)——逻辑回归 人工智能 第14张

LogisticRegression.py:

import numpy as np
from .metrics import accuracy_score

class LogisticRegression:

    def __init__(self):
        """初始化Logistic Regression模型"""
        self.coef_ = None
        self.intercept_ = None
        self._theta = None

    def _sigmoid(self, t):
        return 1. / (1. + np.exp(-t))

    def fit(self, X_train, y_train, eta=0.01, n_iters=1e4):
        """根据训练数据集X_train, y_train, 使用梯度下降法训练Logistic Regression模型"""
        assert X_train.shape[0] == y_train.shape[0], \
            "the size of X_train must be equal to the size of y_train"

        def J(theta, X_b, y):
            y_hat = self._sigmoid(X_b.dot(theta))
            try:
                return - np.sum(y*np.log(y_hat) + (1-y)*np.log(1-y_hat)) / len(y)
            except:
                return float('inf')

        def dJ(theta, X_b, y):
            return X_b.T.dot(self._sigmoid(X_b.dot(theta)) - y) / len(y)

        def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8):

            theta = initial_theta
            cur_iter = 0

            while cur_iter < n_iters:
                gradient = dJ(theta, X_b, y)
                last_theta = theta
                theta = theta - eta * gradient
                if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
                    break

                cur_iter += 1

            return theta

        X_b = np.hstack([np.ones((len(X_train), 1)), X_train])
        initial_theta = np.zeros(X_b.shape[1])
        self._theta = gradient_descent(X_b, y_train, initial_theta, eta, n_iters)

        self.intercept_ = self._theta[0]
        self.coef_ = self._theta[1:]

        return self

    def predict_proba(self, X_predict):
        """给定待预测数据集X_predict,返回表示X_predict的结果概率向量"""
        assert self.intercept_ is not None and self.coef_ is not None, \
            "must fit before predict!"
        assert X_predict.shape[1] == len(self.coef_), \
            "the feature number of X_predict must be equal to X_train"

        X_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])
        return self._sigmoid(X_b.dot(self._theta))

    def predict(self, X_predict):
        """给定待预测数据集X_predict,返回表示X_predict的结果向量"""
        assert self.intercept_ is not None and self.coef_ is not None, \
            "must fit before predict!"
        assert X_predict.shape[1] == len(self.coef_), \
            "the feature number of X_predict must be equal to X_train"

        proba = self.predict_proba(X_predict)
        return np.array(proba >= 0.5, dtype='int')

    def score(self, X_test, y_test):
        """根据测试数据集 X_test 和 y_test 确定当前模型的准确度"""

        y_predict = self.predict(X_test)
        return accuracy_score(y_test, y_predict)

    def __repr__(self):
        return "LogisticRegression()"

使用鸢尾花数据集,因为有三个特征,而逻辑回归只适合二分类问题,所以我们取前2个特征实验:

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

iris=datasets.load_iris()

X=iris.data
y=iris.target

X=X[y<2,:2]
y=y[y<2]

plt.scatter(X[y==0,0],X[y==0,1],color="red")
plt.scatter(X[y==1,0],X[y==1,1],color="blue")
plt.show()

机器学习(6)——逻辑回归 人工智能 第15张

%run f:\python3玩转机器学习\逻辑回归\LogisticRegression.py

from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(X,y,test_size=0.2,random_state=666)

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

log_reg.score(X_test,y_test)
log_reg.predict_proba(X_test)
log_reg.predict(X_test)

机器学习(6)——逻辑回归 人工智能 第16张

准确率100%。

决策边界

机器学习(6)——逻辑回归 人工智能 第17张

机器学习(6)——逻辑回归 人工智能 第18张

绘制决策边界:

def x2(x1):
    return (-log_reg.coef_[0] * x1 - log_reg.intercept_)/log_reg.coef_[1]
    
x1_plot=np.linspace(4,8,1000)
x2_plot=x2(x1_plot)

plt.scatter(X[y==0,0],X[y==0,1],color="red")
plt.scatter(X[y==1,0],X[y==1,1],color="blue")
plt.plot(x1_plot,x2_plot)
plt.show()

机器学习(6)——逻辑回归 人工智能 第19张

其中那个分类错误的红点是训练数据集中的点。

不规则的决策边界绘制方法:

机器学习(6)——逻辑回归 人工智能 第20张

如图,遍历每个点,看它属于哪个类。

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, 7.5, 1.5, 4.5])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
plt.show()

机器学习(6)——逻辑回归 人工智能 第21张

KNN的决策边界:

from sklearn.neighbors import KNeighborsClassifier
knn_clf=KNeighborsClassifier()
knn_clf.fit(X_train,y_train)

knn_clf.score(X_test,y_test)

plot_decision_boundary(knn_clf,axis=[4,7.5,1.5,4.5])
plt.scatter(X[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.show()

机器学习(6)——逻辑回归 人工智能 第22张

knn_clf_all=KNeighborsClassifier()
knn_clf_all.fit(iris.data[:,:2],iris.target)

plot_decision_boundary(knn_clf_all,axis=[4,8,1.5,4.5])
plt.scatter(iris.data[iris.target==0,0],iris.data[iris.target==0,1])
plt.scatter(iris.data[iris.target==1,0],iris.data[iris.target==1,1])
plt.scatter(iris.data[iris.target==2,0],iris.data[iris.target==2,1])

plt.show()

机器学习(6)——逻辑回归 人工智能 第23张

发现黄蓝的决策边界很陡峭,这是因为KNN的k越小,那么模型越复杂,可能会过拟合。

取k=50:

knn_clf_all=KNeighborsClassifier(n_neighbors=50)
knn_clf_all.fit(iris.data[:,:2],iris.target)

plot_decision_boundary(knn_clf_all,axis=[4,8,1.5,4.5])
plt.scatter(iris.data[iris.target==0,0],iris.data[iris.target==0,1])
plt.scatter(iris.data[iris.target==1,0],iris.data[iris.target==1,1])
plt.scatter(iris.data[iris.target==2,0],iris.data[iris.target==2,1])

plt.show()

机器学习(6)——逻辑回归 人工智能 第24张

在逻辑回归中使用多项式特征

机器学习(6)——逻辑回归 人工智能 第25张

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()

机器学习(6)——逻辑回归 人工智能 第26张

%run f:\python3玩转机器学习\逻辑回归\LogisticRegression.py

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()

机器学习(6)——逻辑回归 人工智能 第27张

机器学习(6)——逻辑回归 人工智能 第28张

发现准确率很低,这是因为逻辑回归默认是用一条直线分类的,我们用多项式试一下:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
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)

poly_log_reg.score(X,y)

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()

机器学习(6)——逻辑回归 人工智能 第29张

用二次多项式准确率就比较高了,我们再试一下20次多项式:

poly_log_reg20=PolynomialLogisticRegression(degree=20)
poly_log_reg20.fit(X,y)

poly_log_reg20.score(X,y)

plot_decision_boundary(poly_log_reg20,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()

机器学习(6)——逻辑回归 人工智能 第30张

形状及其不规则,明显是过拟合了,我们可以降低多项式的级数,当然使用正则化是更好的选择。

scikit-learn中的逻辑回归

逻辑回归的正则化:机器学习(6)——逻辑回归 人工智能 第31张

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]<1.5,dtype='int')
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()

机器学习(6)——逻辑回归 人工智能 第32张

用线性逻辑回归:

from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=666)

from sklearn.linear_model import LogisticRegression
log_reg = LogisticRegression()
log_reg.fit(X_train,y_train)

log_reg.score(X_train,y_train)

log_reg.score(X_test,y_test)

机器学习(6)——逻辑回归 人工智能 第33张

发现准确率较低,因为我们造的数据是抛物线。绘制一下:

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()

机器学习(6)——逻辑回归 人工智能 第34张

用二次多项式逻辑回归:

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
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)

机器学习(6)——逻辑回归 人工智能 第35张

返回的penalty就是正则化方式,默认是l2正则,即岭回归。

poly_log_reg.score(X_train,y_train)

poly_log_reg.score(X_test,y_test)

机器学习(6)——逻辑回归 人工智能 第36张

发现准确率比较高了。

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()

机器学习(6)——逻辑回归 人工智能 第37张

20次多项式逻辑回归:

poly_log_reg2=PolynomialLogisticRegression(degree=20)
poly_log_reg2.fit(X_train,y_train)

poly_log_reg2.score(X_train,y_train)

poly_log_reg2.score(X_test,y_test)

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()

机器学习(6)——逻辑回归 人工智能 第38张

发现准确率下降了,根据图就可以看出过拟合了,图形很复杂,但因数据比较弱,所以准确率降低的比较少。

令C=0.1,l2正则:

def PolynomialLogisticRegression(degree,C):#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)

poly_log_reg3.score(X_test,y_test)

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()

机器学习(6)——逻辑回归 人工智能 第39张

图形比上面的要规则一点,但准确率较低。

令C=0.1,换成l1正则:

def PolynomialLogisticRegression(degree,C,penalty='l2'):#C是比重
    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)

poly_log_reg4.score(X_test,y_test)

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()

机器学习(6)——逻辑回归 人工智能 第40张

虽然准确率降低了,但决策边界比较符合我们创造的抛物线了,这是因为l1正则(lasso回归)会尽可能使一些theta为0,起到特征选择。

当然,C这个超参数也可以通过网格搜索来寻找。

OvR与OvO

解决多分类问题:OvR、OvO

OvR(One vs Rest):

机器学习(6)——逻辑回归 人工智能 第41张

OvO(One vs One):

机器学习(6)——逻辑回归 人工智能 第42张

虽然OvO更费时,但准确率要高。

使用鸢尾花数据集来测试:

先取前两个特征:

ovr:

import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

iris=datasets.load_iris()
X=iris.data[:,:2]
y=iris.target

from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=666)

from sklearn.linear_model import LogisticRegression

log_reg=LogisticRegression(multi_class='ovr')
log_reg.fit(X_train,y_train)

log_reg.score(X_test,y_test)

机器学习(6)——逻辑回归 人工智能 第43张

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,8.5,1.5,4.5])
plt.scatter(X[y==0,0],X[y==0,1])
plt.scatter(X[y==1,0],X[y==1,1])
plt.scatter(X[y==2,0],X[y==2,1])
plt.show()

机器学习(6)——逻辑回归 人工智能 第44张

ovo:

log_reg2=LogisticRegression(multi_class='multinomial',solver="newton-cg")#ovo必须换求解方法

log_reg2.fit(X_train,y_train)
log_reg2.score(X_test,y_test)


机器学习(6)——逻辑回归 人工智能 第45张

可见ovo准确率是比ovr高的。

我们再用所有特征测试一下:

X=iris.data
y=iris.target
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)
log_reg.score(X_test,y_test)

log_reg2=LogisticRegression(multi_class='multinomial',solver="newton-cg")
log_reg2.fit(X_train,y_train)
log_reg2.score(X_test,y_test)

机器学习(6)——逻辑回归 人工智能 第46张

ovo准确率达到了1。

其实scikit-learn中有OVR和OVO这两个类,以便所有二分类分类器都可以使用:

ovr:

from sklearn.multiclass import OneVsRestClassifier

ovr=OneVsRestClassifier(log_reg)
ovr.fit(X_train,y_train)
ovr.score(X_test,y_test)

机器学习(6)——逻辑回归 人工智能 第47张

from sklearn.multiclass import OneVsOneClassifier

ovo=OneVsOneClassifier(log_reg)
ovo.fit(X_train,y_train)
ovo.score(X_test,y_test)

机器学习(6)——逻辑回归 人工智能 第48张

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄