00:00
好,那么我们前面这一部分讲完了之后,接下来其实就是我们的核心算法实现了,对吧?好,那么我们的核心算法实现的这个过程当中,大家首先会想到我这个算法里边,它需要我们当时提到需要一个超参数对吧?就是我们要找KN,要找他K个近零,那首先大家能想到K肯定是一个超参数了,对吧?你一开始应该得指定你到底选择几啊,这个比较简单,另外有一个稍微复杂一点的,就是你怎么去判断距离呢?所以我们计算距离是不是得有一个距离函数的定义啊,诶,所以一开始我们得想到啊,这其实我们的一个超参数距离函数定义。
01:00
好,那么这里边我们自然就会想到,按照我们之前讲的标准,我们这里就选这个L1距离和L2距离来给大家简单的做一个解释,那么L1距离其实就是曼哈顿距离,然后没有那个根号,对不对?L2距离就是欧式距离,这个大家都都比较熟,那么我们这里的名字就叫做Le distance,那么它计算的时候是不是要传入两个向量啊?呃,这里边大家注意在我们的这个就是na派和pandas的处理里边,Na派处理里边,我们计算的过程当中可以让这个A。直接用一个矩阵。啊,大家看啊,就是大家看下面我的这个写法,一行实现这样一个距离函数,怎么实现呢?我我们的那个呃,L1的距离它是怎么算的,不开根号就直接求和对不对,然后求和每一项是什么,是不是绝对值啊,对吧?那个差的绝对值对不对?坐标差的绝对值,大家看一下它的这个算法,外面是求和对不对,里边是绝对值对吧?是不是ABS啊呃,然后大家里边看啊,当然这是A减B,直接这样就搞定,当然这里边如果我们要求这个A可以是矩阵的话,它后面要加一个参参数xis等于一,那xis等于一是什么意思呢?这个是轴的意思,对吧?轴等于一,那这个轴的选择其实就是零和一两个维度的选择,就是对于矩阵而言,是不是就是行和列啊,你既然轴。
02:44
是一,他最后的意思就是说我们前面这个sum的运算,运算最后的结果是要把它的结果保存成一列。那也就是说这个sum是对什么sum呢?就是前边我们这里算出来的,这也是一个矩阵对吧,也是一个矩阵,这个矩阵做sum,怎么做sum,如果什么什么参数都不给,这个sum就是把矩阵所有元素都加一遍,如果你给了,最后保存成一列的话,它就是把每一行加起来了。
03:21
所以大家想一下,大家看一下,就是这么这么拉风的一行搞定的,这个这个表达了什么意思啊,他的意思是说,首先里边还有一个A减B2个矩阵相减的对不对?那这里大家注意一下这个要求啊,这里要求是A可以是一个矩阵,B必须只能是一个向量,就不能说B也是矩阵,因为大家就是如果说你给两个矩阵直接去减的话,在这个单派里边,它这里其实是会报错的,它要求说你做减法的时候,只能是前面是一个矩阵,后边是一个向量,大家可以自己去试啊,因为我们在这里边可以随时做实验,对不对调这个方法大家去试一下,那A这里边我们传入的,假如说是一个这个一百零五行四列的一个矩阵的话,B这里边我们传入怎么样的一个形式呢?大家这里注意啊,就只能传入一个一行四。
04:21
列的一个向量,也就是变成了一个行向量对不对?而且行数列数必须跟我们前面的这个A要相等,这样才能做相减对吧?啊,要不然的话,大家之前学这个复习矩阵乘法的时候,已经知道必须是同行的嘛,这里边肯定也必须得这个维度必须同行,那大家想,那么这个减法它又就是可以是减去一行,那减一行代表什么意思呢?就是A里边的每一行都减去B,所以大家会发现那A本来是个矩阵对不对?每一行都减去B,是不是最后还是一个矩阵啊,诶,相当于就是每一行当成一个向量跟B都做了一个减法对吧?诶,所以这是不是就是符合我们要求的呀,就相当于我们一下子就把这一百零五行数据都做了减法了,对不对?
05:15
然后最后再做sum的时候,我们是不是分别对每一行数据,其实就是把它的每个元素加起来啊,这一行里边是不是它有四个维度,我们是不是要把四个维度加起来啊,各行它是不同的数据,那我们其实不需要加对吧?所以大家看这个写法就是直接sum,按照呃,轴是一,也就是最后保存成一列,就是把每一行都加起来,最后保存成一列,直直接这么说好像还是有点有点不知道怎么回事,是吧?啊,那我们在这里还是调一下吧啊,因为我们这里已经有这个X test xx train和这个X test,对不对?那么大家会想到我们按照这个要求的话,是不是可以直接NP ABS X train,这是不是符合我们A的标准,对吧?大家会想到后边是不是可以直接X test做一个减法啊?
06:15
但这里直接运行的话,这里会报错,大家会看到他报什么错呢?诶你就不能直接这么去减对吧,他说这个这个呃呃,我我这里写错了啊,应该是减法对不对,大家发现这里不能直接去减,为什么不能直接去减呢?因为这个形状它是105乘四和45乘四不能直接减。那怎么样可以减呢?大家想到我是不是从这里边对我是不是直接取一行就可以啊,那大家会想到我怎么样的方式是取一行呢?X test里边怎么样能取一行?我如果直接一个取它的这个零,是不是取出来就是第零行啊,是不是就第一行啊,就是我们所说的,所以这个是不是应该满足我们的要求啊,他点shape大家看一眼,是不是刚才我们说到的,诶大家看这个还是有问题的,因为它只是一个一维的数组,对不对,那如果要想转成这个二维数组的话,是不是还是要re ship一下呀?啊,这个稍微有点复杂啊,就是大家测试的时候也可以这么去测,所以这个时候在she,呃呃,这个she不是方法啊,直接是一个属性,是不是就变成441这样的一个,诶,这是一个四一啊。
07:37
哦,我们不应该把它变成列,对吧,我们应该把它变成行啊好,变成一四这样的一个东西是不是就可以了,好,那么我们把这一串放过来。我们的X test放在这里对吧,好,我们看一下现在可不可以,大家看现在是不是就直接把这个就直接算出来了呀。
08:01
大家可以看到得到的这个结果是不是还是一个矩阵,这个矩阵是什么呢?就是我们X train里边的每一个元素减去,呃,这个我还是把前面可能给大家得打出来是吧,要不然大家这个还是看不明白啊。好,那么大家看一眼,我前面的这个xtra,这里边第一行是5.43 4.51.5对不对?呃,大家先大概记住这个,因为后面数有点多啊,5.43这样的,然后我们这里的这个取出来的这个X test的第一行是5.8对不对,5.45.8是不是一减减的是0.4啊,第二个那个是不是三三和2.7 2.71减是不是0.3啊,然后后边一减啊,0.60.4是不是就是对应元素都减掉啊,然后这是不是第二行全减去这个得到的这个元素啊啊,所以它是这样的一个计算啊,那么然后大家想这个,最后我们再把这个做一个sum,做出来是什么东西呢?如果我们直接把它做sum的话,大家会看到啊,这个直接sum sum出来就是就是一个数,就是把所有的都加起来了,对不对,那么我们这里。
09:30
边假如说想要让它按照行,每一行加起来,最后生成一列的话,那后边就要加一个XX等于一,所以大家看一下这个这个操作啊,最后出来之后是不是1.711.3,就是大家看到每一个数,就是代表我们刚才剪完了之后,最后求和的那个值对不对啊,大家看就是就是这样的一个操作啊,所以也就是呃,Python里边它经常就是因为它本来是一个脚本语言嘛,所以有时候为了脚本的方便,它很多操作都可以,就是结合起来,最后写成一行,这个脚本调用是不是特别方便啊?呃,但是我们理解起来可能稍微有一点麻烦,就是大家得知道每一步它到底做的是什么事情,好,那这个我就先把这个。
10:21
删掉了啊好,这是我们的这个距离函数的定义,当然了,这里我们只定义了一个这个L1对吧,那同样大家可以定义L2对不对,跟L1类似,我们也是指定它可以计算输入,A是一个矩阵,然后B是一个向量,一个行向量对吧?好,那么接下来我们看它这个怎么做呢?直接return l2是不是外面得开根号了,所以NP掉这个number派里边的方法啊,SQRT,这是不是求开根号啊,求根好,然后里边是什么方法呢?里边是不是还是要求和啊,是不是还是要求和跟刚才的方式一样对吧?然后求和它的内容是什么呢?把什么东西求和呢?
11:16
是不是还是A减B啊,要求差,这个时候是不是还得平方啊,大家看它方便就方便,在我们即使是矩阵跟行向量去做减法,完了之后也可以直接平方,直接这么算得到的还是一个矩阵,对吧?那当然这个完了之后做求和的时候,是不是我们还是按照每一行去求的呀,对吧,你算了那个平方之后,还是一行去求,所以是不是跟上面的写法一样,这里还是。等于一啊,所以大家看一下就是这就是Python里边我把这个这就不要空格了,大家看的清楚一点,就是这是求跟,诶这个好像我写错了啊,应该是求和里边放在这里对不对,对吧?好,所以大家会看到我们整个是把里边的这一整个这一部分去求根,然后呢,求根的这一部分是什么呢?是是平方的和对不对,平方和怎么算呢?平方和前面这一部分是平方,然后求和的时候,我们根据这个轴等于一把它每一行做一个求和,对吧?啊,所以这就是一行搞定我们的距离函数,好,那接下来哎,大家看这个前面这个光光看这个就就整了半天啊,然后接下来是我们真正核心的分类器,对不对,分类器实现那这个。
12:48
分类器里边如果我们要按照标准的方式来写的话,这可能就涉及到这个面对对象的写法了,对吧?定义一个class class k,呃,那这里边大家看这个Python里边的面对对象写法,一个类定义后面括号里边的内容就相当于它继承的那个父类,对吧?我们这里边按照这个新新式的类的继承写法的话,所有类都应该是object类的一个子类,所以我们在这里这样去写,那么它里边就可以定义对应的方法了,对不对?首先大家注意啊,首先我们需要定义什么呢?定义一个初始化方法啊,这是类里边必须要有的啊,这个是,呃,或者说这是大家看它的形式是这个两。
13:48
两个下划线,然后init,然后两个下划线,它是类的构造方法,呃,所以这就是我们跟大家面对对象学过的那些东西都都类似对吧?只不过就是说Python里边有有他的一些特殊的写法而已,所以我们这里定义一个in方法,那么它里边的参数传什么呢?这里注意类里边的参数第一个都要传一个self啊,那这个self是什么意思呢?Self指代的是这个类的实力啊,它它不是类本身啊,它指代的是类的实力,那self.class才是指的类本身,那这个大家区分的清楚对不对,就是类类实类的实例和类本身,这个我们在Java和SKY里边都有对应的概念啊,所以第一个参数是self,这是所有类类的方法都得第一个参数是self,好,那么第二个参数,大家想初始化的时候,我们可能需要什么呢?初。
14:48
只画一个KNN这个分类器的时候要什么参数呢?就是我们一开始提到过的超参数,对吧?你既然是KNN嘛,那是不是你到底有几个精灵,这个是不是我们需要知道啊,啊,那我们这里边叫kn neighbors,这就是我们指定的这个净灵数量对吧?默认我们可以给它附一个一默认我选取最近的那一个近灵,然后它的类别就作为我测试样本点的类别,对不对?另外还有一个超参数应该叫什么?
15:27
前面我们一开始做的是什么呢?是不是定义距离函数啊啊,那是不是我们还有一个超参数应该传入的是呃,或者叫这个构造调用构造函数的时候应该传入的参数是不是它的距离函数啊呃,所以我们这里边定义一个叫Dis fok,这是不是距离函数的意思啊,定义一个这样的一个参数,那么我们默认它就是我们的前面定义好的L1吧,L distance,这是不是一个我们的函数名啊,对吧?所以我们直接就把这个函数名赋给了这个Dis Dis funk好,那么这是它的一个构造方法,那里边既然是构造方法嘛,那是不是得把它自己类的一些属性本身要附进去啊呃,所以self点它的属性就全是self点,对吧,N neighbors GH。
16:25
等于n neighbors,对吧?当然大家觉得这个词太长的话,我写完整的词是因为大家会理解起来方便一些,大家如果要是想缩写自己随便啊,Self。另外大家会想到这个Dis funk是不是也得附进来啊,它自己本身的一个属性对不对,等于Dis funk,好啊,这就是我们的构造函数,然后大家会想到我们在这个所有的机器学习算法里边,是不是一开始应该有一个呃,训练模型的方法啊,一般训练模型方法。
17:04
一般我们在机器学习里边训练模型的方法都叫fit啊,之前我们是不是定义的也是fit啊啊,所以这里边我们也还是fit啊,那这是一个监督学习问题,是不是F应该是X跟Y传进来,然后去训练模型啊,那么我们这个KN前面我们说过了,训练怎么训练呢?我们我们怎么训练这个模型啊,其实好像我们就把所有的这个XY输入进去就对了,对不对?就等着你再来一个测试点,然后算距离就好了,是不是我们就没有训练的这个过程啊,哎,所以这个过程其实就很简单,我们这个训练的过程其实就是把XY传进来就完事,对不对啊,所以这个就我们定义一个self里边有一个X train吧,这是它的训练数据,对不对?就等于这个X,这是训练啊,然后那么y train。
18:05
是不是就等于Y啊,啊,所以只要把它附进来就好,呃,别的其实什么都什么都不需要做,那关键我们的方法核心的算法应该在哪里实现啊,是不是应该在模型的预测方法里面实现啊,大家想我们模型训练完了之后,是不是要做预测的呀?模型预测方法那同样在这个标准的机器学习监督机器学习算法里边,呃,它的这个预测方法一般就叫predict,对对不对,Predict,呃,那么大家想这个也是啊,先传入Excel,然后预测方法需要传什么参数呢?训练的时候XY要传入,那预测的时候传什么呢?传测试数据的XY,对吧?哎,大家想我需要传Y吗?我预测的话是不是应该是只需要传X,不需要传Y啊,对吧?我预测这个点它应该分到哪一类,我应该就是不知道它分到哪个类的,对吧?这个时候才是有意义的,所以我们直接把X传入就可以了,好,那接下来呢,就会想到,呃,就是我们核心的这个预测了,对吧?怎么怎么样去预测这个东西呢?第一步大家会想到它最后要返回什么东西,我最后是不是应该返回一个它的预测分类啊,对吧?所以是一个Y的predict这样的一个东西,对不对?那假如我这里边XX传入的是一组样本的话,那我这个返回应该是一组分类值对不对啊,就是我这里如果要是还可以传传矩阵的话,好,那么大家就会想到,一开始我是不是应该先初始化一下。
19:52
加这个预测数组啊,对吧,初始化预测分类数组啊,那么我们的y predict,大家想到这个初始化,初始化的时候我们可以给一个空数组,但是大家会想到我其实是到底有多少个数据,其实应该知道的,对吧,我不应该是一个变长的数组对不对?我最后这个预测,假如说我传入十个预测的样本点的话,我最后是不是应该输出十个预测的Y啊,所以那么这里边我是不是应该预初始化一个固定长度的数组啊,那固定长度我们这里边是不是可以把它初始化成零啊,因为我们的分类就是012嘛,那一开始我们默认它都是零就好了,大家看这个初始化一个零数组可以怎么,怎么初始化呢?用单派里边的zero方法。
20:52
这是不是就是初始化的一个零数组啊啊zero,然后里边里边要传的参数其实就是它的,呃,第一个参数就是它的具体形状了啊,有两个参数,一个参数是它的形状,形状是什么呢?是不是跟我们的X的形状应该一样啊呃,注意这里边行数是不是应该跟它一样,我们X大家传入的这个X是什么呢?是不是可能就是跟这个测试数据一样的这个状形状啊,是不是四十五行四列,这就是表示45个点对不对?所以我们我们的Y是不是最后传入45个数据,是不是也应该是45 45Y应该也是四十五行啊,所以我们的行数是不是要用X的SHAPE0啊,是不是这个啊,就是我们传入多少行,这里就是多少行,对吧?然后Y预测出来的列是不是?
21:52
应该是自己固定的,就是一列啊,这个形状就是固定的啊,然后后边我们再定义一个d type,就是说它的数据的类型到底是什么类型呢?我们这里定义一个self跟train的类型要一样,对吧。
22:12
就是我们前面已经定义好的这个这里的Y是什么类型,我们这里就是什么类型,对吧?啊,这是尽管我们这里是零嘛,那大家知道这个南派里边它的初始化的时候,呃,大家可以看一眼啊NP.zero那么我们这里边如果要是给。给一个这个,呃,假如说就是一二啊,大家看一眼这个东西,它生成的这个数据类型是不是一个float类型啊,对,所以这里边我们还得给他做一个指定对吧,比方说我们这里如果指定d type等于。呃,前面的这个y train点第一的话。
23:00
那么大家看这里是不是就变成整形了,哎,所以这是一个简单的写法啊,大家知道就可以了。呃,所以这一行就相当于我们初始化的这样的一个预测的,呃,这个数组对吧,结果的分类数组好,那么接下来我们就要真正的做预测了,对吧。那做预测的这个过程当中,大家会想到我们首先根据我们的算法,大家会想到分成这么几步对不对,这几步里边我们看第一步就是计算数据和各个训练数据之间的距离对不对?那在我们的这个问题里边,我们是不是不止有可能不止一组数据啊,我们这个考虑的问题比较复杂,就是X有可能是有可能是个矩阵对吧?比方说我们把这个测试数据直接传进去,这是不是45个数据啊,45组数据,那所以我们是不是首先应该是便利这个45个数据对不对,然后一个一个算它的分类对不对?哎,所以大家会想到我是不是应该有一个for循环啊,对吧?电力输入的X数据点好,那么首先我这里要有一个for。
24:24
啊,For,这里大家看一下这个写法啊,Four X,我把每一个叫做X test,这是不是我输入进来的一个测试点啊,这是单独的一个测试点对吧?但是我前面又要把I拿出来,那大家想到这个I应该是什么东西啊?是不是我要选取这个测试点它它的那个序号啊,第几个测试点对不对?然后我是不是就可以把它保存到这个y predict的对应的那个位置去啊,是不是我要用这个序号来做保存啊?呃,所以这里我相当于是把它的每一个X所有的点里边的每一个点的值和它对应的这个索引下下标对吧?角标是不是同时拿出来了,这就有点像我们字字典里面的KY同时拿出来那种状态,对吧?呃,那么这个我们怎么样去印什么呢?放这个印对吧,我们平常都是直接range对不对,呃,Range的话拿出。
25:24
来的应该就只是它的这个值对不对,那这里边我们有另外的一个写法什么呢?啊,就是在Python里边有另外的一个一个内置方法啊叫呃,Inu,呃,Inumerate对吧,就是我们的枚举对不对?这个枚举方法我们要枚举这个X的话,拿出来的其实就是一个元组,相当于那么这个元组前边就是它的序号,后边就是它的值对吧,Innumerate,好,那么我们有了这个方法之后,现在就可以针对这个X test是不是就是每一个数据点啊,对吧,每取出每一个数据点的序号I和呃数据对吧,X test。
26:24
我们写的详细一点啊好,那接下来我们是不是就按这个步骤来了,第一步要做什么来着,是不是计算计算距离啊对吧,是X X test,他要跟谁计算距离呢。看一眼我们这个测试数据与各个训练数据之间的距离对不对,所以我们这里第一步是不是要跟训所有啊,所有训练数据计算距离对吧?啊,所以这是我们的第一步,然后第二步我们应该做什么呢?第二步是不是得到的距离做个排序啊好呃,得到的距离按照由近到远。
27:27
排序好,然后接下来的第三步,大家会想到是不是我们就应该怎么样了,是不是要选取其中最小的K个点,然后统计它出现的频率啊,对吧,选取。呃,最近的K个点统计类别出现频率最高的那个,对吧?呃,当然就是说,呃,我们这里边可能需要把它分成几步来做,对吧?有可能分成几步来做这个,到时候我们做到这里的时候再给大家来说,呃,那么选取最近的K个点,我们可能先要去保存它的,保存它们对应的分类类别,对吧?我们先保存下来,然后下一步再统计对不对,统计类别中出现。
28:49
频率最高的那个,然后这个是不是就是我们的y predict啊呃,付给y predict y predict本身是一个数组,我们现在取的是不是Di,所以我们现在是不是付给y predict I呀,对吧?所以这就是我们基本的一个流程,基本的一个想法。
我来说两句