使用逻辑回归时怎么利用网格搜索来查找degree,c等超参数

来源:9-8 OvR与OvO

慕粉0602482145

2018-06-03

老师,课上您说到如果在实际应用中逻辑回归的超参数是利用网格搜索来找的,我自己试了一下,下面是代码,您帮我看看哪里不对

#您课上举得例子
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
#数据集分成训练数据集和测试数据集
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)
##########这里已经能够看到SCORE是多少##############
#这里是重点,我想使用网格搜索来查找多项式回归和逻辑回归的超参数
C_PARM = [0.1,0.2,0.3,0.4,0.5]
param_grid = [
    {
        'degree': [i for i in range(1, 11)], 
        'C': [i for i in C_PARM]
    }
]
from sklearn.model_selection import GridSearchCV
grid_search = GridSearchCV(log_reg, param_grid)
grid_search.fit(X_train,y_train)  
#这一步进行fit的时候已经报错,我觉得是因为逻辑回归没有degree这个超参数
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

def PolynomialLogisticRegression(degree,C):
    return Pipeline([
        ('poly', PolynomialFeatures(degree=degree)),
        ('std_scaler', StandardScaler()),
        ('log_reg', LogisticRegression(C=C))
    ])
####老师,我最想表达的是怎么用网格搜索来搜索degree和C这两个超参数,让其跟后面的pipeline一起使用





写回答

1回答

liuyubobobo

2018-06-04

非常好的问题。如何将自定义的Pipline对象应用于sklearn内置的网格搜索确实是课程没有讲的一个sklearn使用上的语法细节:)


首先,你在31行的注释分析的是正确的。由于此时,你在构建grid_search的时候,传入的算法是log_reg。而log_reg是LogisticRegression的对象,但是创建LogisticRegression是并不需要参数degree,所以,这里会报错。


正确的做法是,我们要对你创建的PolynomialLogisticRegression这个函数返回的对象进行网格搜索。这个函数的逻辑是返回了一个Pipeline的对象,这个Pipeline的对象中创建PolynomialFeatures时使用了degree这个参数。


为了方便起见,在这里,我为这个PolynomialLogisticRegression添加上了默认值。

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


我们需要针对poly_log_reg这个对象进行网格搜索:)


但是,在这里,poly_log_reg中包含三部分,每部分都有自己的参数。按照你写的param_grid,参数名称直接写degree和C,GridSearchCV是无法认得这些参数名隶属于哪一部分的。所以,在这种情况下,我们在设置param_grid的时候,参数名要显示地表明这个参数属于哪个部分。表示的方法是:

{$Pipeline中的对象名称}__{$参数名}

即,在Pipeline中的对象名称,加上双下换线(__),再加上参数名称。


所以,我们在网格搜索中,要搜索的两个参数名称应该是:

poly__degree
log_reg__C

其中的poly和log_reg,是你在实例化这个Pipeline对象的时候,给每一部分起的那个名称。


综上,此时我们的param_grid,要这样声明:

C_PARM = [0.1,0.2,0.3,0.4,0.5]
param_grid = [
    {
        'poly__degree': [i for i in range(1, 11)], 
        'log_reg__C': [i for i in C_PARM]
    }
]


现在,就可以按照以前一样的方法使用GridSearchCV啦:)

grid_search = GridSearchCV(poly_log_reg, param_grid)
grid_search.fit(X_train,y_train)


整理一遍,我们的整个代码就是这样的:

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

# 待进行网格搜索的算法    
poly_log_reg = PolynomialLogisticRegression()

# 准备待搜索的参数列表
C_PARM = [0.1,0.2,0.3,0.4,0.5]
param_grid = [
    {
        'poly__degree': [i for i in range(1, 11)], 
        'log_reg__C': [i for i in C_PARM]
    }
]

# 实例化GridSearchCV进行网格搜索
grid_search = GridSearchCV(poly_log_reg, param_grid)
grid_search.fit(X_train,y_train)


看起来写了很多,但是自己整理一遍,会发现其实这个语法非常简单:)


加油!

12
4
lemonlxn
回复
liuyubobobo
嗯嗯,那我再来总结一下,如果用最优参数进行predict ,要这样写:grid_search.best_estimator_.predict(X_test),如果用grid_search.predict(X_test) ,代表用默认参数来预测,这里的默认参数,对应老师您这里写的 degree = 1 ,C = 0.1
2019-07-18
共4条回复

Python3入门机器学习 经典算法与应用  

Python3+sklearn,兼顾原理、算法底层实现和框架使用。

5850 学习 · 2437 问题

查看课程