决策边界 逻辑回归中的多项式特征 多分类问题


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、决策边界?

1、回顾逻辑回归原理

在这里插入图片描述

1、引入我们自己实现的逻辑回归算法

import numpy as np
from sklearn.metrics import accuracy_score
class LogicRegression:
    def __init__(self):
        self._theta=None
        self.interception_=None
        self.coef_=None
    def _sigmoid(self,t):
        return 1./(1.+np.exp(-t))
    def fit(self,X_train,y,eta=0.01,n_iters=1e3):
        assert X_train.shape[0]==y.shape[0],\
        "the size of X_train must be equal the size of y_train"
        #损失函数
        def J(X_b, y, theta):
            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')  # 防止eta不合理出错

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

    # 梯度下降过程
        def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e3, epsilon=1e-8):
            theta = initial_theta
            i_iters = 0
            while i_iters < n_iters:
                last_theta = theta  # 保存上次theta
                gradient = dJ(X_b, y, theta)
                theta = theta - eta * gradient
                if (np.abs(J(X_b, y, theta) - J(X_b, y, last_theta)) < epsilon):
                    break
                i_iters += 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, initial_theta, eta, n_iters=1e3)
        self.interception_ = self._theta[0]
        self.coef_ = self._theta[1:]
        return self
    #获得概率向量
    def predict_proba(self,X_predict):
        x_b = np.hstack([np.ones((len(X_predict), 1)), X_predict])

        return self._sigmoid(x_b.dot(self._theta))
    #获得预测结果 0或1
    def predict(self,X_predict):
        proba=self.predict_proba(X_predict)
        return np.array(proba>=0.5,dtype=int)
    def score(self,X_test,y_test):
        y_predict=self.predict(X_test)
        return accuracy_score(y_test,y_predict)
        #分类准确度

2、引入决策边界

在这里插入图片描述
为了可视化,先假设样本有两个特征
在这里插入图片描述
因为是分类问题,所以x1,x2都是样本特征。可以用颜色来代表分类

1、一个简单的案例 仍然使用上篇的鸢尾花数据

from sklearn import datasets
iris=datasets.load_iris()
x=iris.data
y=iris.target
x=x[y<2,:2]
y=y[y<2]
def x2(x1):
    return (-Logicreg.coef_[0]*x1-Logicreg.interception_)/Logicreg.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()

在这里插入图片描述
此时可能有人会好奇,上篇中,我们的分类准确度是1,但是这里有一个红色点一看就不对,那是因为这个红色点是训练数据集,而不是测试数据集。
我们可以只绘制测试数据集来查看。

plt.scatter(x_test[y_test==0,0],x_test[y_test==0,1],color='red')
plt.scatter(x_test[y_test==1,0],x_test[y_test==1,1],color='blue')
plt.plot(x1_plot,x2_plot)
plt.show()

在这里插入图片描述

		确实准确度是1

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

这里的决策边界是一条直线,我们可以直接算出方程绘制出来。但是对于有的决策边界,是很复杂的,我们没有办法算出方程。
在这里我们举一个例子,但对于具体的绘制过程,并不要求大家学会。只要理解其思想就可以。
在这里插入图片描述

	比如在这里,我们将两个坐标轴分别拆分成很小的部分
	之后再将每一个对应位置的分类用不同的颜色绘制出来,因为划分的单位很小
	所以绘制出来之后的点就可以据此分开,形成一个决策边界。

1、不规则决策边界举例

import numpy as np
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_camp=ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
    
    plt.contourf(x0,x1,zz,linewidth=5,camp=custom_camp)
plot_decision_boundary(Logicreg,[4,7.5,1.5,4.5])
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()

在这里插入图片描述

	根据密集点的颜色不同便可以区分出边界

KNN也可以解决分类问题,自然也有决策边界
但是KNN的决策边界并不能由公式计算得来

from sklearn.neighbors import KNeighborsClassifier
knn=KNeighborsClassifier()
knn.fit(x_train,y_train)
plot_decision_boundary(knn,[4,7.5,1.5,4.5])
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()

在这里插入图片描述
我们知道,KNN天然可以解决多分类问题
这里我们仍然使用鸢尾花数据,但是我们仍只是用两个特征,为了可视化
但是此时有三种分类

knn_all=KNeighborsClassifier()
knn_all.fit(iris.data[:,:2],iris.target)
plot_decision_boundary(knn_all,[4,7.5,1.5,4.5])
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()

在这里插入图片描述

		我们可以看出这个决策边界显然太过于复杂,我们知道
		knn算法中默认的n为5,n越小,则越会过拟合,越复杂
		如下图,我们传入n为50,可以明显看出决策边界简单了不少
knn_all=KNeighborsClassifier(n_neighbors=50)
knn_all.fit(iris.data[:,:2],iris.target)
plot_decision_boundary(knn_all,[4,7.5,1.5,4.5])
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()

在这里插入图片描述

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

1.为什么要在逻辑回归中使用多项式特征

我们知道,逻辑回归只能解决二分类问题,但是有的决策边界可能是复杂的多项式,而不是简单的线性,但是简单的逻辑回归中的决策边界却是简单的线性方程,比如我们自己实现的逻辑回归中的x2

但若决策边界如下图所示呢?
在这里插入图片描述
此时的决策边界对于x1和x2来说是非线性的,但是对于x1²和x2²来说是线性的,因此我们可以在逻辑回归的基础上添加上多项式回归,以便于更好的找到决策边界

2、

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],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.show()

在这里插入图片描述

1、直接用逻辑回归(线性)

log_reg=LogicRegression()
log_reg.fit(x,y)
plot_decision_boundary(log_reg,[-4,4,-4,4])
plt.scatter(x[y==0,0],x[y==0,1],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.show()
log_reg.score(x,y)

在这里插入图片描述

分类准确度只有0.615

2、使用多项式回归的逻辑回归

from sklearn.preprocessing import StandardScaler,PolynomialFeatures
from sklearn.pipeline import Pipeline
#逻辑回归中引入多项式
def polylogicregression(degree):
    return Pipeline([
        ('poly',PolynomialFeatures(degree=degree)),
        ('std_sca',StandardScaler()),
        ('log_reg',LogicRegression())
    ])

degree=2时

poly_logreg=polylogicregression(degree=2)
poly_logreg.fit(x,y)
plot_decision_boundary(poly_logreg,[-4,4,-4,4])
plt.scatter(x[y==0,0],x[y==0,1],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.show()
poly_logreg.score(x,y)

在这里插入图片描述

	准确度变为了0.9

degree=20时
在这里插入图片描述

	分类准确度为0.89,但是我们可以看出边界变复杂了,是由于过拟合
	这显然不是我们想要的。

三、sklearn中的逻辑回归

sklearn中的逻辑回归自带正则化
但是这里的正则化与之前讲的有所不同
在这里插入图片描述
左边是之前讲的l1,l2正则项,但是逻辑回归中它的系数是加在损失函数之前。这个整体作为新的损失函数。若C过大,则会导致J(theta)的权重增大。反之会导致正则项的权重增大。

1、案例

import matplotlib.pyplot as plt
import numpy as np
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):  #随机选取20个点使其分类变为1
    y[np.random.randint(200)]=1  #相当于加上了噪音
plt.scatter(x[y==0,0],x[y==0,1],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.show()

在这里插入图片描述

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_test,y_test)
plot_decision_boundary(log_reg,[-4,4,-4,4])
plt.scatter(x[y==0,0],x[y==0,1],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.show()
log_reg.score(x_test,y_test)

在这里插入图片描述

引入多项式

from sklearn.preprocessing import StandardScaler,PolynomialFeatures
from sklearn.pipeline import Pipeline
#逻辑回归中引入多项式
def polylogicregression(degree):
    return Pipeline([
        ('poly',PolynomialFeatures(degree=degree)),
        ('std_sca',StandardScaler()),
        ('log_reg',LogisticRegression())
    ])
p_log=polylogicregression(degree=2)
p_log.fit(x_train,y_train)
plot_decision_boundary(p_log,[-4,4,-4,4])
plt.scatter(x[y==0,0],x[y==0,1],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.show()
p_log.score(x_test,y_test)

在这里插入图片描述
引入参数C

from sklearn.preprocessing import StandardScaler,PolynomialFeatures
from sklearn.pipeline import Pipeline
#逻辑回归中引入多项式
def polylogicregression(degree,C):
    return Pipeline([
        ('poly',PolynomialFeatures(degree=degree)),
        ('std_sca',StandardScaler()),
        ('log_reg',LogisticRegression(C=C))
    ])
p_log2=polylogicregression(degree=2,C=0.1)
p_log2.fit(x_train,y_train)
plot_decision_boundary(p_log2,[-4,4,-4,4])
plt.scatter(x[y==0,0],x[y==0,1],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.show()
p_log2.score(x_test,y_test)

在这里插入图片描述
修改degree

from sklearn.preprocessing import StandardScaler,PolynomialFeatures
from sklearn.pipeline import Pipeline
#逻辑回归中引入多项式
def polylogicregression(degree,C):
    return Pipeline([
        ('poly',PolynomialFeatures(degree=degree)),
        ('std_sca',StandardScaler()),
        ('log_reg',LogisticRegression(C=C))
    ])
p_log2=polylogicregression(degree=20,C=0.1)
p_log2.fit(x_train,y_train)
plot_decision_boundary(p_log2,[-4,4,-4,4])
plt.scatter(x[y==0,0],x[y==0,1],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.show()
p_log2.score(x_test,y_test)

在这里插入图片描述
引入正则化penalty

from sklearn.preprocessing import StandardScaler,PolynomialFeatures
from sklearn.pipeline import Pipeline
#逻辑回归中引入多项式
def polylogicregression(degree,C,penalty='l2'):
    return Pipeline([
        ('poly',PolynomialFeatures(degree=degree)),
        ('std_sca',StandardScaler()),
        ('log_reg',LogisticRegression(C=C,penalty=penalty))
    ])
p_log2=polylogicregression(degree=20,C=0.1,penalty='l1')
p_log2.fit(x_train,y_train)
plot_decision_boundary(p_log2,[-4,4,-4,4])
plt.scatter(x[y==0,0],x[y==0,1],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.show()
p_log2.score(x_test,y_test)

在这里插入图片描述

四、多分类问题

我们知道逻辑回归只能解决二分类问题。但是通过
OVO (one vs one) 和OVR(one vs rest)来将多分类转化为二分类,以此可以将二分类器来解决多分类问题

1、OVO

在这里插入图片描述

2、OVR

在这里插入图片描述

3、比较

ovo比ovr准确,但ovo比ovr耗时长,我们可以通过分类次数看出。ovr是n²,ovo是n

4、例子(逻辑回归中的多分类):

SKlearn中的逻辑回归默认使用的是ovr来解决多分类问题

为了可视化,我们首先采用两个特征
from sklearn import datasets
iris=datasets.load_iris()
x=iris.data
y=iris.target
x=x[:,:2] #为了可视化,我们仍先选择两个特征
plt.scatter(x[y==0,0],x[y==0,1],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.scatter(x[y==2,0],x[y==2,1],color='g')
plt.show()

在这里插入图片描述

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
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)
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_camp=ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
    
    plt.contourf(x0,x1,zz,linewidth=5,camp=custom_camp)

首先使用默认的ovr

plot_decision_boundary(log_reg,axis=[4,8.5,1.5,4.5])
plt.scatter(x[y==0,0],x[y==0,1],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.scatter(x[y==2,0],x[y==2,1],color='g')
plt.show()

在这里插入图片描述
在这里插入图片描述

使用ovo

log_reg2=LogisticRegression(multi_class='multinomial',solver='newton-cg')
log_reg2.fit(x_train,y_train)
log_reg2.score(x_test,y_test)
plot_decision_boundary(log_reg2,axis=[4,8.5,1.5,4.5])
plt.scatter(x[y==0,0],x[y==0,1],color='r')
plt.scatter(x[y==1,0],x[y==1,1],color='b')
plt.scatter(x[y==2,0],x[y==2,1],color='g')
plt.show()

在这里插入图片描述
在这里插入图片描述

	上述的准确度都不高是因为我们使用的信息较少,只使用了两个样本特征

使用鸢尾花全部的数据


from sklearn import datasets
iris=datasets.load_iris()
x=iris.data
y=iris.target
x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=666)
log_reg3=LogisticRegression()
log_reg3.fit(x_train,y_train)
log_reg3.score(x_test,y_test)

0.9473684210526315

log_reg3=LogisticRegression(multi_class='multinomial',solver='newton-cg')
log_reg3.fit(x_train,y_train)
log_reg3.score(x_test,y_test)

1.0

5、ovo和ovr两个类

ovo和ovr不仅可以解决逻辑回归中的多分类,还可以解决其他多分类问题。

from sklearn.linear_model import LogisticRegression
log_reg=LogisticRegression()
from sklearn.multiclass import OneVsRestClassifier
ovr=OneVsRestClassifier(log_reg)
ovr.fit(x_train,y_train)
ovr.score(x_test,y_test)

0.9473684210526315

from sklearn.multiclass import OneVsOneClassifier
ovo=OneVsOneClassifier(log_reg)
ovo.fit(x_train,y_train)
ovo.score(x_test,y_test)

1.0

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值