Pyts入门之时间序列的分类---K近邻算法及调参小技巧(二)

18 篇文章 11 订阅
6 篇文章 28 订阅

简介

书接上文(2021.11.05),在介绍了pyts的时间序列简单特征提取之后,我们来介绍一下对时间序列的分类算法,从KNN(k-nearest neighbors)算法开始,一篇文章介绍一个分类算法。因为工作上的一些烦心事情,最近一直都没写文章,可能关注我的小伙伴都忘了为啥关注我,实在抱歉,那么我们进入正题,首先需要先对KNN算法(分类)有个大概的了解:
1.它不是K-means算法(K-means是无监督的聚类算法,新手经常会把它们搞混)。
2.它是监督学习(supervised learning)的算法。
3.K代表选取K个最近的邻居(neighbors)进行投票,哪个种类的投票多则分类成哪个,如果K=1,那么距离它最近的样本是哪个类就是哪个类。
4.距离有多种定义,我们常说的空间中两点的距离为欧几里得距离(Euclidean distance)。
5.KNN对数据集的结构比较敏感。
6.在实际使用前,通常对数据集进行特征提取(或者说降维),能够提高算法的稳定性和准确度,例如人脸识别中opencv使用的haar casade分类。

在这里插入图片描述
上图来自wiki,图中绿圆圈为待分类的样本点,K=3时选取离它最近的三个点(实线圆圈),包含一个蓝方和两个红三角,那么它就被分类为红三角,K=5时选取最近的五个点(虚线圆圈),包含三个蓝方和两个红三角,那么它就被分类为蓝方。

经过上面的介绍,我想你们也会发现这个算法有三个参数是非常重要的:

1.K的个数(neighbors)。也就是近邻的选取数,选的越大,算法更稳定,但会损失一定的区别性,比如当近邻数等于样本数的时候,所有的点都会被作为分类参考,那我不管怎么分类新的样本都是同样的结果。

2.距离选取(metric)。怎么度量点与点之间的距离决定了判断样本点的远近。有不少经典距离,比如
欧几里得距离(sqrt(sum((x - y)^2))),即相减的平方差。
曼哈顿距离(sum(|x - y|)),即相减的绝对值。
Minkowski 距离(sum(w * |x - y|p)(1/p)),q=1为绝对距离,q=2为欧几里得距离。

3.权重影响(weights)。引入权重的想法是考虑近的点对样本点的影响比远的点更大,一种常见的做法是引入1/d,d为该点和样本点的距离。

实践

from pyts.classification import KNeighborsClassifier
from pyts.datasets import load_gunpoint
X_train, X_test, y_train, y_test = load_gunpoint(return_X_y=True)
clf = KNeighborsClassifier()
clf.fit(X_train, y_train)
clf.score(X_test, y_test)
#score:0.913333333333333333333333

首先是默认参数的结果,准确率也就是0.91333,接下来我们将试着调整参数来提高准确率。
默认参数也即不带任何传入参数是以下这样的:
n_neighbors=1, weights=‘uniform’, algorithm=‘auto’, leaf_size=30, p=2, metric=‘minkowski’, metric_params=None, n_jobs=1

参数说明
n_neighbors=1近邻个数为1,为整数
weights=‘uniform’默认不添加权重,如果为’distance’,则添加1/d的权重
algorithm=‘auto’有{‘auto’, ‘ball_tree’, ‘kd_tree’, ‘brute’}四种计算近邻的方法,在计算性能(大样本集)上各有不同
leaf_size=30ball_tree或kd_tree的叶子个数,会影响到叶子的构建速度,也是性能的影响
p=2minkowski距离的p值,等于2等同于欧几里得距离,等于1等同于曼哈顿距离
metric=‘minkowski’距离规则,可传入不同的距离,如“euclidean”,“manhattan”等,更多看sklearn的DistanceMetric类
metric_params有些距离的特有参数,默认是None
n_jobs=1搜索近邻使用的并行线程数,设成-1表示用所有的资源搜索,默认为1

那么我们主要改变n_neighbors,weights,p三个参数来看结果的变化:

from sklearn.model_selection import GridSearchCV #网格搜索
parameters = {'weights':('uniform', 'distance'),'n_neighbors':[1,2,3,4,5],'p':[1,2]} #定义搜索参数
clf_grid = GridSearchCV(clf, parameters)#传入之前定义好的实例和参数
clf_grid.fit(X_train, y_train)
clf_grid.cv_results_ #打印在训练集上的结果

我们对参数进行了网格搜索来寻找最好的参数,cv_results_会打印很长一串,我们取其中的一部分来说明:

'params': [{'n_neighbors': 1, 'p': 1, 'weights': 'uniform'},
  {'n_neighbors': 1, 'p': 1, 'weights': 'distance'},
  {'n_neighbors': 1, 'p': 2, 'weights': 'uniform'},
  {'n_neighbors': 1, 'p': 2, 'weights': 'distance'},
  {'n_neighbors': 2, 'p': 1, 'weights': 'uniform'},
  {'n_neighbors': 2, 'p': 1, 'weights': 'distance'},
  {'n_neighbors': 2, 'p': 2, 'weights': 'uniform'},
  {'n_neighbors': 2, 'p': 2, 'weights': 'distance'},
  {'n_neighbors': 3, 'p': 1, 'weights': 'uniform'},
  {'n_neighbors': 3, 'p': 1, 'weights': 'distance'},
  {'n_neighbors': 3, 'p': 2, 'weights': 'uniform'},
  {'n_neighbors': 3, 'p': 2, 'weights': 'distance'},
  {'n_neighbors': 4, 'p': 1, 'weights': 'uniform'},
  {'n_neighbors': 4, 'p': 1, 'weights': 'distance'},
  {'n_neighbors': 4, 'p': 2, 'weights': 'uniform'},
  {'n_neighbors': 4, 'p': 2, 'weights': 'distance'},
  {'n_neighbors': 5, 'p': 1, 'weights': 'uniform'},
  {'n_neighbors': 5, 'p': 1, 'weights': 'distance'},
  {'n_neighbors': 5, 'p': 2, 'weights': 'uniform'},
  {'n_neighbors': 5, 'p': 2, 'weights': 'distance'}]

这一长串是你定义搜索的参数所有可能结果的排列组合,实际上就是去一个个训练,看看哪个最好。

'rank_test_score': array([ 4,  4,  1,  1,  4,  4, 17,  1,  9,  9, 13, 13, 13,  9, 20,  9, 13,
         4, 19, 17]

这一串数字就是对上面这么多测试结果的排序,可以看到第三个和第四个的结果是最好的,同时细心的朋友也会发现引入权重的结果总体上比没引入要好。由于第三个在参数上和默认的是一样的,那么我们来验证一下第四个在测试集上的结果:

clf = KNeighborsClassifier(n_neighbors=1,weights='distance',p=2)
clf.fit(X_train, y_train)
clf.score(X_test, y_test)
#0.91333333

你可能会说:这不是没提升吗?这网格搜索在搜索什么呢。请注意,在训练集上cv出来的结果好不能保证测试集上效果好,但是在训练集上cv的结果很差放在测试集上很大可能效果差。所以网格搜索就是个参考。而真实世界的机器学习更加复杂,在测试集上的效果好也不意味着你在新的样本上效果好,但遵守一些基本常识可以提高泛化性能。

clf = KNeighborsClassifier(n_neighbors=1,weights='distance',p=1)
clf.fit(X_train, y_train)
clf.score(X_test, y_test)
#0.9533333333333334

实际上把距离切换成曼哈顿之后,测试集上的准确率会提高不少,来到了0.953333,但是这其实是个小样本集,它的shape是(50,150),较为推荐的做法是先进行降维之后再拟合,尽管数据会不好看,但提升了现实中的泛化性能。

参考资料

1.https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm
2.https://scikit-learn.org/stable/modules/generated/sklearn.metrics.DistanceMetric.html?highlight=distance#sklearn.metrics.DistanceMetric
3.https://pyts.readthedocs.io/en/stable/modules/classification.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值