美文网首页机器学习、深度学习与人工智能
机器学习系列(八)——超参数GridSearch调节与模型优化

机器学习系列(八)——超参数GridSearch调节与模型优化

作者: Ice_spring | 来源:发表于2019-06-10 22:56 被阅读32次

    超参数

    超参数与模型参数

    超参数是运行算法之前需要指定的参数;
    模型参数是算法运行过程中学习的参数,往往需要不断随算法运行更新

    knn算法比较特殊,它没有模型参数,只有超参数,k即是超参数。
    机器学习算法工程师调参需要调的是超参数,超参数影响最终的模型参数进而影响模型效果。

    如何寻找好的超参数

    调节参数首先要有一定的领域专业知识,其次是根据经验得来的经验数值(sklearn中算法的很多默认数值都是经验数值),最后是通过实验搜索最优超参数。

    '''手写数字knn实现'''
    import numpy as np
    from sklearn import datasets
    digits = datasets.load_digits()
    x = digits.data
    y = digits.target
    
    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)
    
    from sklearn.neighbors import KNeighborsClassifier
    '''超参数设定'''
    knn_clf = KNeighborsClassifier(n_neighbors=3,random_state=666)
    knn_clf.fit(x_train,y_train)
    knn_clf.score(x_test,y_test)
    out:0.966
    

    上面是用sklearn中knn算法默认超参数进行的模型fit,下小节将通过网格搜索来寻找最优参数:

    knn算法中最优的n_neighbors

    寻找最优的k思想很简单,就是针对不同的k都建立一个knn分类器,看哪个k的分类准确率高,循环即可解决:

    '''最优k搜索'''
    best_score=0
    best_k=-1
    for k in range(1,11):
        
        knn_clf = KNeighborsClassifier(n_neighbors=k)
        knn_clf.fit(x_train,y_train)
        score = knn_clf.score(x_test,y_test)
        if score > best_score:
            best_k = k
            best_score = score
            
    print("best_k = ",best_k)
    print("best_score = ",best_score)
    

    结果如下:


    best_k

    如果搜索得到的最优值在搜索范围的边界,最好进行拓展搜索,因为往往准确率是连续变化的,最优值出现在边界,则很可能在你规定的范围外面。

    knn中的其它超参数

    • 带权重距离distances
      比如k=3时,虽然有时a类占比最多为2个,但是最近的3个里面,b类的一个的距离要远远近于另外两个,故应给予更多考虑。假设距离为1,3,4,取倒数后1,1/3,1/4,1>7/12,故按此规则应是1获胜。这样还有另外一个优点,比如当分3类时,出现平票现象,此时按距离的权重还是能决出高低,可以自己尝试编写带权重的距离。
    best_method = ""
    best_score=0
    best_k=-1
    for method in ("uniform","distance"):
        for k in range(1,11):
            '''加入weight参数'''
            knn_clf = KNeighborsClassifier(n_neighbors=k,weights = method)
            knn_clf.fit(x_train,y_train)
            score = knn_clf.score(x_test,y_test)
            if score > best_score:
                best_k = k
                best_score = score
                best_method = method
    print("best_method is",best_method)            
    print("best_k = ",best_k)
    print("best_score = ",best_score)
    

    结果如下:


    method
    • 明氏距离参数p
      当weights="uniform"时,其实没必要进行p参数的搜索,因为当weights=“uniform”时,使用任意p度量求得的distances序列,经排序后得到的nearest序列都是一样的(Rn空间中范数的等价性) 。例如:当p=1时,KNeighborsClassifier类中的nearest=[4,2,1,3];当p为任意正整数时,仍然有nearest=[4,2,1,3] 因而无论p怎么变,最终求得的knn_clf_score都是一样的,故而超参数p无意义。 而当weights=“distance”时,取不同的p值,distances序列经排序后得到的nearest序列会不一样,会影响到最终求得的knn_clf_score。
    '''最优的明氏距离参数p搜索'''
    %%time#计算运行时间
    best_p = -1
    best_score=0
    best_k=-1
    for k in range(1,11):
        for p in range(1,6):
            knn_clf = KNeighborsClassifier(n_neighbors=k,weights = "distance",p=p)
            knn_clf.fit(x_train,y_train)
            score = knn_clf.score(x_test,y_test)
            if score > best_score:
                best_k = k
                best_score = score
                best_p = p
    print("best_p = ",best_p)
    print("best_k = ",best_k)
    print("best_score = ",best_score)
    

    结果如下:


    m_p

    网格搜索GridSearch

    上面我们看到,超参数之间可能出现依赖关系,如何进行一次命令就完成网格搜索呢,sklearn中可以这样实现。

    GridSearch

    首先定义搜索的参数列表:

    '''定义搜索参数网格'''
    param_grid=[
        {
            'weights':['uniform'],
            'n_neighbors':[i for i in range(1,11)]
            
        },
        {
            'weights':['distance'],
            'n_neighbors':[i for i in range(1,11)],
            'p':[i for i in range(1,6)]
        }
    ]
    

    然后实例化GridSearch搜索对象并执行搜索:

    '''搜索'''
    knn_clf = KNeighborsClassifier()
    
    from sklearn.model_selection import GridSearchCV
    grid_search = GridSearchCV(knn_clf,param_grid)#实例化一个网格搜索对象,1指定对哪个分类器进行网格搜索,2搜索参数是什么
    
    grid_search.fit(x_train,y_train)
    

    搜索结果:

    search_result
    可以用命令给出最优分类器参数:
    grid_search.best_estimator_
    best_estimator
    最佳准确率和对应的参数值:
    accuaracy_param
    可以发现即使指定了random_state,这里找到的最优参数和上面自行搜索找到的仍然不一样,这是因为网格搜索中,CV用的评价标准是一种更加复杂的方式,即交叉验证
    注:不是用户传入的参数,而是根据用户传入的参数,由类计算出来的参数,名字后跟下划线,这是一种编码规范。
    于是将当前分类器设置为最优分类器:
    re_apply

    GridSearch中的其它参数

    GridSearch工作原理其实是创建多个分类器进行搜索,实际这个工作可以并行处理以加快速度,n_jobs默认为1相当于串行。如果你的计算机双核,可以传2(我的虚拟机2核),传参数-1则表示计算机所有核都用于网格并行搜索,可以用%%time测试时间,参数verbose可以在搜索过程输出一些信息,默认为2最好。

    '''gridsearch中其它参数'''
    grid_search = GridSearchCV(knn_clf,param_grid,n_jobs=2,verbose=2)
    '''gridsearch工作原理其实是创建多个分类器进行搜索,实际这个工作可以并行处理,n_jobs默认为1是串行
       如果你的计算机双核,可以传2(我的虚拟机2核),传-1表示计算机所有核都用于网格搜索
       可以用%%time测试时间
       verbose可以在搜索过程输出一些信息
    '''
    grid_search.fit(x_train,y_train)
    

    更多距离度量

    • 余弦相似度
    • 调整余弦相似度
    • pearson相关系数
    • jaccard相似系数

    不同距离度量有不同的最佳应用场景
    度量metrics默认是明氏,可以根据应用场景修改为其它距离,如jaccard,pearson等。

    相关文章

      网友评论

        本文标题:机器学习系列(八)——超参数GridSearch调节与模型优化

        本文链接:https://www.haomeiwen.com/subject/vxqxfctx.html