n_neighbors:默认为5,就是k-NN的k的值,选取最近的k个点。 weights:默认是uniform,参数可以是uniform、distance,也可以是用户自己定义的函数。uniform是均等的权重,就说所有的邻近点的权重都是相等的。distance是不均等的权重,距离近的点比距离远的点的影响大。用户自定义的函数,接收距离的数组,返回一组维数相同的权重。 algorithm:快速k近邻搜索算法,默认参数为auto,可以理解为算法自己决定合适的搜索算法。除此之外,用户也可以自己指定搜索算法ball_tree、kd_tree、brute方法进行搜索,brute是蛮力搜索,也就是线性扫描,当训练集很大时,计算非常耗时。kd_tree,构造kd树存储数据以便对其进行快速检索的树形数据结构,kd树也就是数据结构中的二叉树。以中值切分构造的树,每个结点是一个超矩形,在维数小于20时效率高。ball tree是为了克服kd树高纬失效而发明的,其构造过程是以质心C和半径r分割样本空间,每个节点是一个超球体。 leaf_size:默认是30,这个是构造的kd树和ball树的大小。这个值的设置会影响树构建的速度和搜索速度,同样也影响着存储树所需的内存大小。需要根据问题的性质选择最优的大小。 metric:用于距离度量,默认度量是minkowski,也就是p=2的欧氏距离(欧几里德度量)。 p:距离度量公式。在上小结,我们使用欧氏距离公式进行距离度量。除此之外,还有其他的度量方法,例如曼哈顿距离。这个参数默认为2,也就是默认使用欧式距离公式进行距离度量。也可以设置为1,使用曼哈顿距离公式进行距离度量。 metric_params:距离公式的其他关键参数,这个可以不管,使用默认的None即可。 n_jobs:并行处理设置。默认为1,临近点搜索并行工作数。如果为-1,那么CPU的所有cores都用于并行工作。 考虑距离?不考虑距离? 当K=3时,如下图所示,由投票法蓝色点胜出,于是绿色的点就归为蓝色点的那一类。但是这样分类我们虽然考虑了离绿色节点最近的三个点,但是却忽略了这三个点到绿色点的距离,从图中可以看出红色的点其实是离绿色的点最近,当我们考虑距离时,我们需要将距离附一个权重值,离得越近,权重越大,通常将距离的导数作为权重:
此外,考虑距离的KNN在平票时也可解决相应的问题
寻找最优超参数weights:['uniform','distance']
def main():
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,random_state=666)
from sklearn.neighbors import KNeighborsClassifier
# 寻找最好的k,weights
best_k=-1
best_score=0
best_method=''
for method in ['uniform','distance']:
for i in range(1,11):
knn_clf=KNeighborsClassifier(n_neighbors=i,weights=method)
knn_clf.fit(x_train,y_train)
scores=knn_clf.score(x_test,y_test)
if scores>best_score:
best_score=scores
best_k=i
best_method=method
print('最好的k为:%d,最好的得分为:%.4f,最好的方法%s'%(best_k,best_score,best_method))
if __name__ == '__main__':
main()
更多关于距离的定义,可以得到领一个超参数p:
对最优的明可夫斯基距离相应的p进行搜索:
def main():
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,random_state=666)
from sklearn.neighbors import KNeighborsClassifier
# 寻找最好的k,weights
best_k=-1
best_score=0
best_p=-1
for i in range(1,11):
for p in range(1,6):
knn_clf=KNeighborsClassifier(n_neighbors=i,weights='distance',p=p)
knn_clf.fit(x_train,y_train)
scores=knn_clf.score(x_test,y_test)
if scores>best_score:
best_score=scores
best_k=i
best_p=p
print('最好的k为:%d,最好的得分为:%.4f,最好的p为%d'%(best_k,best_score,best_p))
if __name__ == '__main__':
main()
最好的k为:3,最好的得分为:0.9889,最好的p为2 从上面的例子我们可以看出,有些超参数之间可能会存在相互依赖的关系,比如在上面的程序中,当weights='distance'时,才牵扯到p这个超参数。如何将更好的一次性将我们想要的超参数都列出来,运行一遍程序就可以找到我们想要的超参数呢?使用网格搜索我们可以帮我们解决这个问题,被封装在sklearn中的Grid Search 中。 GridSearchCV 提供的网格搜索从通过 param_grid 参数确定的网格参数值中全面生成候选。例如,下面的 param_grid:
param_grid = [
{'C': [1, 10, 100, 1000], 'kernel': ['linear']},
{'C': [1, 10, 100, 1000], 'gamma': [0.001, 0.0001], 'kernel': ['rbf']},
]
探索两个网格的详细解释: 一个具有线性内核并且C在[1,10,100,1000]中取值; 另一个具有RBF内核,C值的交叉乘积范围在[1,10,100,1000],gamma在[0.001,0.0001]中取值。 在本例中:
def main():
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,random_state=666)
from sklearn.neighbors import KNeighborsClassifier
#Grid Search定义要搜索的参数
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)]
}
]
knn_clf=KNeighborsClassifier()
from sklearn.model_selection import GridSearchCV
#n_jobs采用几个核来处理,-1代表计算机有几个核就用几个核进行并行处理,搜索过程中verbose可以进行信息输出,帮助理解搜索状态
grid_search=GridSearchCV(knn_clf,param_grid,n_jobs=-1,verbose=1)
grid_search.fit(x_train,y_train)
#返回网格搜索最佳分类器
print(grid_search.best_estimator_)
#返回网格搜索最佳分类器的参数
print(grid_search.best_params_)
#返回网格搜索最佳分类器的分数
print(grid_search.best_score_)
knn_clf=grid_search.best_estimator_
print(knn_clf.score(x_test,y_test))
if __name__ == '__main__':
main()
Fitting 3 folds for each of 60(10+50) candidates, totalling 180 fits
[Parallel(n_jobs=-1)]: Done 34 tasks | elapsed: 1.6s
[Parallel(n_jobs=-1)]: Done 180 out of 180 | elapsed: 30.6s finished
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
metric_params=None, n_jobs=1, n_neighbors=3, p=3,
weights='distance')
{'n_neighbors': 3, 'weights': 'distance', 'p': 3}
0.985386221294
0.983333333333
在衡量距离时,其实还有一个非常重要的概念就是数据归一化Feature Scaling
从上面的例子可以看出,如果发现时间以天为计量单位,样本间的距离被发现时间所主导,若发现时间以年为计量单位,样本间的距离又被肿瘤大小主导,这就表明如果我们不对样本的数据进行处理的话,直接去计算距离结果将会是有偏差的。 数据归一化 解决方案:将所有的数据映射同一尺度
import numpy as np import matplotlib.pyplot as plt #最值归一化 x=np.random.randint(0,100,size=100) print(x) normal_x=(x-np.min(x))/(np.max(x)-np.min(x)) print(normal_x) #均值方差归一化 x2=np.random.randint(0,100,(50,2)) print(x2) x2=np.array(x2,dtype=float) x2[:,0]=(x2[:,0]-np.mean(x2[:,0]))/np.std(x2[:,0]) x2[:,1]=(x2[:,1]-np.mean(x2[:,1]))/np.std(x2[:,1]) plt.scatter(x2[:,0],x2[:,1]) plt.show() x:[49 27 88 47 6 89 9 98 17 72 46 46 80 62 28 38 0 27 22 14 2 79 70 73 15 57 85 6 11 76 59 62 23 32 82 78 0 45 8 82 13 81 99 61 43 21 45 61 93 63 66 57 78 60 50 8 29 63 74 8 25 55 10 69 3 77 41 24 15 23 21 31 36 78 94 52 12 1 23 99 8 12 15 37 75 75 27 14 31 75 6 56 29 96 23 0 22 98 86 10] normal_x:[ 0.49494949 0.27272727 0.88888889 0.47474747 0.06060606 0.8989899 0.09090909 0.98989899 0.17171717 0.72727273 0.46464646 0.46464646 0.80808081 0.62626263 0.28282828 0.38383838 0. 0.27272727 0.22222222 0.14141414 0.02020202 0.7979798 0.70707071 0.73737374 0.15151515 0.57575758 0.85858586 0.06060606 0.11111111 0.76767677 0.5959596 0.62626263 0.23232323 0.32323232 0.82828283 0.78787879 0. 0.45454545 0.08080808 0.82828283 0.13131313 0.81818182 1. 0.61616162 0.43434343 0.21212121 0.45454545 0.61616162 0.93939394 0.63636364 0.66666667 0.57575758 0.78787879 0.60606061 0.50505051 0.08080808 0.29292929 0.63636364 0.74747475 0.08080808 0.25252525 0.55555556 0.1010101 0.6969697 0.03030303 0.77777778 0.41414141 0.24242424 0.15151515 0.23232323 0.21212121 0.31313131 0.36363636 0.78787879 0.94949495 0.52525253 0.12121212 0.01010101 0.23232323 1. 0.08080808 0.12121212 0.15151515 0.37373737 0.75757576 0.75757576 0.27272727 0.14141414 0.31313131 0.75757576 0.06060606 0.56565657 0.29292929 0.96969697 0.23232323 0. 0.22222222 0.98989899 0.86868687 0.1010101 ]
sklearn中的StandardScaler 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) #sklearn中的StandardScaler from sklearn.preprocessing import StandardScaler standardscaler=StandardScaler() standardscaler.fit(x_train) #均值 print(standardscaler.mean_) #方差 print(standardscaler.scale_) x_train_standard=standardscaler.transform(x_train) x_test_standard=standardscaler.transform(x_test) print(x_train_standard) from sklearn.neighbors import KNeighborsClassifier knn_clf=KNeighborsClassifier(n_neighbors=3) knn_clf.fit(x_train_standard,y_train) scores=knn_clf.score(x_test_standard,y_test) print(scores) 总结:
此外,使用K近邻算法还可以解决回归问题,预测房价,成绩等。用平均距离预测
以上这篇K最近邻算法(KNN)---sklearn+python实现方式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持社区。 | |||