今天我们要做一件特别的事,从头开始撰写我们自己的分类器,如果你刚开始接触机器学习,这是一个重要的里程碑。因为如果你能跟上进度并独立完成,这意味着你已学会机器学习谜团里最重要的一块。今天我们要撰写的分类器是k-NN算法的简化版:它是最简单的分类器之一。
我们从上一篇文章中的代码开始撰写一个机器学习流水线,我们做过一个简单的实验,导入一个数据集把它拆分成训练数据集及测试数据集,使用训练数据集来训练分类器,使用测试数据集测试其准确度
编写分类器是我们今天的重点,之前我们把从软件库导入分类器改写为自定义的分类器,其余部分将会保持不变。上一篇文章中我们运行代码所看到的准确度超过90%,这是我们撰写分类器要达到的目标。
所以我们需要做的第一件事就是更正导入的分类器为自己编写的,要做到这一点我们要为分类器加入类我把它称为ScrappyKNN,我们添加两个方法:fit—它负责训练及predict—它负责预测。我们会编写一个随机分类器,而随机意味着我们只是猜测标签。首先我们将会添加 一些代码到fit及predict在fit那里我把训练数据储存在这个类:
那么让我们再次运行它看看结果怎么样?在鸢尾花的数据集有三种不同类型的花准确度应为约26%。
我们之前的分类器的使用当我们开始这个练习时准确率应为90%以上,我们看看可否做得更好,要这样做我们要设置分类器,而它是依照k-NN算法运行,这里是这个算法的运作,我们看到图中的绿点及红点:
试想一下我们在屏幕上看到的小点就是存储在fit方法里的训练数据,比如说玩具数据集,现在想象一下我们要求为这个测试点作预测,在这里我会用灰色画出来:
我们怎样才能这样做?在k-NN算法分类器中它的工作原理像听起来一样,我们找到的训练点跟测试点最接近,这一点就是最近的比邻:
然后我们预测这个测试点带有相同的标签,例如我们预测这个测试点是绿色的,因为这是其最近邻居的颜色:
另一个例子在这里,如果我们有一个测试点我们猜想它是红色的:
现在来看看中间这个?
试想一下这一点跟最近的绿点及最近的红点距离相等,它们不分胜负,那么我们怎样分类?其中一种方法是我们可以随机打破平局,还有另一种方法就是利用k值,K是在我们作预测时要考虑的邻居数目,如果k为1我们就看到最近的训练点:
但是假设k为3我们就要看看最接近的三个邻居:
在这种情况下其中两个是绿色另一个是红色,。票以作预测最主要的类。
这个算法有更多的细节不过这也足够让我们开始要撰写代码,首先我们需要找到最近邻居的方法,要做到这一点我们要量度两点之间的直线距离,就像用尺子量度,有一条公式称为欧式距离。
公式看起来像这样,它可以量度两点之间距离,有点像勾股定理直角边长的A平方及B的平方加起来等于斜边长C的平方
你可以把这个想像为A或前两个特征之间的差异,同样地你可以把这个想像为B或第二对特征之间的差异,而我们算出来的距离就是斜边长度。
现在我们计算出两维空间中的距离,是由于在玩具数据集里我们只有两个特征。但如果这里有三个特征或者是三维空间呢?我们身在一个立方体仍然可以想像在空间里怎样使用直尺量度距离。
但如果这里有四个特征或者是四维空间呢?就像鸢尾花?现在我们身在超立方体这样我们很难想象出来。好消息是无论哪个维度欧式距离均以同样的方式运算,随着越来越多的特征我们要添加更多条件到方程式,你们可在网上找到更多细节。
现在我们撰写欧式距离的代码有很多办法做到这一点,我们会使用一个称为scipy的库它经已由Anaconda安装,这里A及B是数字功能的列表,比如说A是距离训练数据的一点,而B是距离测试数据的一点,这个函数会返回两者之间的距离。
这就是我们所需要的计算,现在我们来看看分类器的算法:为测试点作预测,我们要计算所有训练点的距离,然后我们要预测测试点跟最接近的一点具有相同标签,找出离测试点最接近的训练点这里我们把k硬编码为1,我们撰写k-NN的分类器,k变量不会在代码中出现。只要我们一直找到最接近的点,在这个方法中我们将会循环遍历所有训练点并记录最接近的点。要记住,我们把训练点储存在fit函数,而x_train 含有特征,开始时我会计算测试点跟第一个训练点的距离。来看实现:
到此为止我们有一个 有效的近邻分类器,我们尝试运行它看看其准确度,正如你所看到的准确度超过90%。当你们自己运行时,准确性可能不同,是因为训练测试的随机的,现在你们可以明白并编写这些编码,味着你们可以从头开始撰写一个简单的分类器。
这种算法有些不同的利弊,你们都可以在网上找到的。基本的好处就是它相对上容易理解,对于处理某些问题效果很好。而缺点是速度慢,因为它要遍历每一个训练点以作一个预测,而且重要的是正如前面文章提及过有些特征比其他的特征提供更多信息。
但是在k-NN算法没有一个简单的方法来表示,长远来看我们需要一个分类器能够学习特征之间更为复杂的关系,以及我们尝试预测的标签。
决策树是一个很好的例子。
片段1:
import random
class ScrappyKNN():
def fit(self,x_train,y_train):
self.x_train = x_train
self.y_train = y_train
def predict(self,x_test):
predictions = []
for row in x_test:
label = random.choice(self.y_train)
predictions.append(label)
return predictions
from sklearn import datasets
iris = datasets.load_iris()
x = iris.data
y = iris.target
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size =.5)
my_classifier = ScrappyKNN()
my_classifier.fit(x_train,y_train)
predictions = my_classifier.predict(x_test)
from sklearn.metrics import accuracy_score
print("ScrappyKNN:",accuracy_score(y_test,predictions))
片段2:
from scipy.spatial import distance
#定义欧氏距离计算方法
def euc(a,b):
return distance.euclidean(a,b)
class ScrappyKNN():
def fit(self,x_train,y_train):
self.x_train = x_train
self.y_train = y_train
def predict(self,x_test):
predictions = []
for row in x_test:
label = self.closest(row)
predictions.append(label)
return predictions
def closest(self,row):
best_dist = euc(row,self.x_train[0])
best_index = 0
for i in range(1,len(self.x_train)):
dist = euc(row,self.x_train[i])
if dist < best_dist:
best_dist = dist
best_index = i
return self.y_train[best_index]
from sklearn import datasets
iris = datasets.load_iris()
x = iris.data
y = iris.target
from sklearn.model_selection import train_test_split
x_train,x_test,y_train,y_test = train_test_split(x,y,test_size =.5)
my_classifier = ScrappyKNN()
my_classifier.fit(x_train,y_train)
predictions = my_classifier.predict(x_test)
from sklearn.metrics import accuracy_score
print("ScrappyKNN-NEW:",accuracy_score(y_test,predictions))