超参数
超参数与模型参数
超参数是运行算法之前需要指定的参数;
模型参数是算法运行过程中学习的参数,往往需要不断随算法运行更新
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)
搜索结果:
可以用命令给出最优分类器参数:
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等。
网友评论