【学习笔记】cs229机器学习笔记(二)
-
机器学习 Day 2
10/23 学习内容:
1) python的基本语法
2 ) 继续学习cs229机器学习
多元线性回归
-
多特征量下线性回归的假设形式可看作两个向量的乘积
-
同样的,代价函数也可以看做关于θ的带有一个n+1维向量的函数
-
多元情况与单元情况下的梯度下降算法中的θ参数的更新方法是相同的
梯度下降运算中的实用技巧
-
特征缩放(fearture scaling)
IEDA:将各个特征值的范围约束到大约-1~+1的范围内或大致相近的范围内,以便于使得梯度下降更快,收敛循环次数更少。
METHOD:
1) 将特征值的范围除以最大值
2) 均值归一化
=:
如何确定梯度下降算法是否收敛?
-
未收敛时,
在每一次迭代后应当下降 -
自动收敛测试判定:收敛后,相邻的两次代价函数值差小于一个阈值(如:0.001)
-
作
的变化图也可判断代价函数是否收敛
多项式回归
-
用一个新的特征代替多个特征,以获得更好的模型与数据的拟合效果
eg: S=a*b;
补充:
添加高阶项的时候,也增加了模型的复杂度。随着模型复杂度的升高,模型的容量以及拟合数据的能力增加,可以进一步降低训练误差,但导致过拟合的风险也随之增加。
过拟合例子:
-
此时函数图像穿过了每一个样本点,所有的训练样本都落在了拟合的曲线上,训练误差接近与0。 可以说是近乎完美的模型了。但是,这样的曲线与我们最开始数据的来源(一个二次方程加上一些随机误差)差异非常大。如果从相同来源再取一些样本点,使用该模型预测会出现非常大的误差。
-
类似这种训练误差非常小,但是新数据点的测试误差非常大的情况,就叫做模型的过拟合。 过拟合出现时,表示模型过于复杂,过多考虑了当前样本的特殊情况以及噪音(模型学习到了当前训练样本非全局的特性),使得模型的泛化能力下降。
(术语"泛化"指的是一个假设模型能够应用到新样本的能力。) -
解决方式:
- 降低模型复杂度,例如减小上面例子中的degree;
- 降维,减小特征的数量;
- 增加训练样本;
- 添加正则化项.
标准方程法
- 提供一种求解θ的解析解法,相比于梯度下降算法的多次迭代收敛,可以一次性求解θ的最优值。
- 当J(θ) (n+1维向量的函数)的偏导数为零时,即能够求得使得代价函数最小化的θ的值。
-
-
正规方程normal equation和其不可逆性
正规方程
- 在前面我们学习了使用梯度下降法来计算参数最优解,其过程是对代价函数相对于每个参数求偏导数,通过迭代算法一步一步进行同步更新,直到收敛到全局最小值,从而得到最优参数值。而正规方程则是通过数学方法一次性求得最优解。
- 通过下面这个公式得出参数θ最优解。
不可逆情况
即
不可逆
原因:- 多余特征(线性相关)
- 太多特征(例如:m<=n)
- 删除一些特征,或者正则化
正规方程与梯度下降法的比较
- 可以将万作为一个界限,当数量小于10000时,直接选择正规方程,当大于10000时,就可以考虑是否换用梯度下降法
- 在前面我们学习了使用梯度下降法来计算参数最优解,其过程是对代价函数相对于每个参数求偏导数,通过迭代算法一步一步进行同步更新,直到收敛到全局最小值,从而得到最优参数值。而正规方程则是通过数学方法一次性求得最优解。
-
分类问题
逻辑回归(分类算法)
想要预测的0,1二元分类问题
sigmoid将分类的结果很好的映射成为[0,1]之间的概率
- 逻辑回归最大的优势在于它的输出结果不仅可以用于分类,还可以表征某个样本属于某类别的概率。
- 逻辑斯谛函数将原本输出结果从范围(−∞,+∞)(−∞,+∞) 映射到(0,1),从而完成概率的估测。
- 逻辑回归得判定的阈值能够映射为平面的一条判定边界,随着特征的复杂化,判定边界可能是多种多样的样貌,但是它能够较好地把两类样本点分隔开,解决分类问题。
- 求解逻辑回归参数的传统方法是梯度下降,构造为凸函数的代价函数后,每次沿着偏导方向(下降速度最快方向)迈进一小部分,直至N次迭代后到达最低点。
-
逻辑回归补充
逻辑回归的损失函数
-
如果采用线性回归的损失函数采用的平方损失函数
即
则会导致成本函数sigmoid()是一个非凸函数,收敛于局部最低点而无法收敛在全局最低点上。
如图
因此逻辑回归中在针对二分类问题上以下代价函数:
进而得到的损失函数能保证是凸函数:
它保证了一种代价“惩罚机制”,随着预测值与实际值偏差越大,代价函数将激增。
梯度下降找θ最小化
同时更新所有的θ值,与线性回归的梯度下降规则完全相同。。
但是假设两者不相同。 - 实现方法上向量法便于所有θ的同步更新。
比梯度下降更高效的优化算法
优化逻辑回归的速度,主要考虑对于J(θ)和偏导项计算的效率优化。
优点在于收敛速度更快并且学习速率α可以自动调整,缺点在于算法较为复杂。-
共轭梯度法Conjugate gradient
-
-
多分类问题(one-vs-all)
主要思想:将二元分类问题拓展到n元分类问题中去。
采用“一对余”方法,将其分解为n个二元分类问题,选定一个i类别的训练集为正样本(1),其它设定为负样本(0)。然后通过二元分类,得到 ( )的逻辑回归分类器。
其中( )=P(y=i|x;θ).
最后,在多类别分类时,在n个分类器中选取max{( )}对应的i即可。
-
过拟合overfitting(高方差)问题
- 当函数的变量很多、训练集较小时,函数能够很高的拟合训练集的数据,而无法泛化到新的样本中去。
e.g:线性回归下的三种情形:- 欠拟合(高偏差)
- 恰好
- 过拟合(高方差)
解决方案 - 减少选取变量的数量(人工检查,模型选择算法)(问题:减少特征变量的同时也舍弃了问题中的一些信息)
- 正则化(保留所有的特征变量但是减少参数值的大小或者是数量级)
- 当函数的变量很多、训练集较小时,函数能够很高的拟合训练集的数据,而无法泛化到新的样本中去。
-
为什么通常Relu比sigmoid和tanh强,有什么不同?(收藏一下)
主要是因为它们gradient特性不同。sigmoid和tanh的gradient在饱和区域非常平缓,接近于0,很容易造成vanishing gradient的问题,减缓收敛速度。vanishing gradient在网络层数多的时候尤其明显,是加深网络结构的主要障碍之一。相反,Relu的gradient大多数情况下是常数,有助于解决深层网络的收敛问题。Relu的另一个优势是在生物上的合理性,它是单边的,相比sigmoid和tanh,更符合生物神经元的特征。
而提出sigmoid和tanh,主要是因为它们全程可导。还有表达区间问题,sigmoid和tanh区间是0到1,或着-1到1,在表达上,尤其是输出层的表达上有优势。为什么引入Relu呢?
第一,采用sigmoid等函数,算激活函数时(指数运算),计算量大,反向传播求误差梯度时,求导涉及除法,计算量相对大,而采用Relu激活函数,整个过程的计算量节省很多。
第二,对于深层网络,sigmoid函数反向传播时,很容易就会出现梯度消失的情况(在sigmoid接近饱和区时,变换太缓慢,导数趋于0,这种情况会造成信息丢失,从而无法完成深层网络的训练。
第三,Relu会使一部分神经元的输出为0,这样就造成了网络的稀疏性,并且减少了参数的相互依存关系,缓解了过拟合问题的发生
copied from ReLu(修正线性单元)、sigmoid和tahh的比较
-
Tensorflow搭建神经网络初步实践(基础)
(正好学习到了cs229的神经网络部分,开始跟着教程实践一下!)
神经网络的基本模型是神经元,基本模型其实就是乘加运算。
一些概念:-
基于TensorFlow的NN:用张量表示数据,用计算图搭建神经网络,用会话执行计算图,优化线上的权重,得到模型。
-
张量是多维数组,用阶表示张量的维度。
-
0阶张量称作标量,是一个单独的数
-
1阶张量称作向量,是一维数组
-
2阶张量称作矩阵,表示一个二维数组
-
n阶张量,表示为t[[[[[...]]]]](n 个)
-
-
数据类型:主要有tf.float32,tf.int32
-
计算图:搭建神经网络法人计算过程,只是承载一个或多个计算节点的一张图,只搭建网络,不运算。
-
会话:执行计算图中的节点运算
-
神经网络的参数:指的是神经网络线上的权重w,一般会先随机生成。生成参数方法是让w=tf.Variable(生成方式)
神经网络中常见的生成随机数/数组的函数有:
tf.random_normal()生成正态分布随机数
tf.truncated_normal()生成去掉过大偏离点的正态分布随机数
tf.random_uniform()生成均匀分布的随机数
补充(正态分布和均匀分布(高斯分布))
Ex1:(张量加法)
import tensorflow as tf a=tf.constant([1.0,2.0]) b=tf.constant([3.0,4.0]) result=a+b print(result)
Output:
Tensor("add:0",shape=(2,),dtype=float32)
Ex2:(矩阵乘法)
import tensorflow as tf #计算图的实现 x=tf.constant([[1.0,2.0]]) w=tf.constant([[3.0],[4.0]]) y=tf.matmul(x,w) print(y) #会话的with结构实现 with tf.Session() as sess: print(sess.run(y))
Output:
Tensor("matmul1:0",shape(1,1),dtype=float32) [[11.]]
-
-
Tensorflow搭建神经网络初步实践(前向传播)
神经网络的实现过程
1.准备数据集、提取特征作为输入喂给神经网络(NN)
2.搭建NN结构,从输入到输出(先搭建计算图再用会话执行)
( NN 前向传播算法计算输出)
3.大量特征数据喂给NN,迭代优化NN参数
(NN反向传播算法优化参数训练模型)
4.使用训练好的模型预测和分类
前向传播就是搭建模型的计算过程,让模型具有推理能力 可以针对一组输入给出相应的输出。
EX1:#coding:utf-8 import tensorflow as tf #输入层 x=tf.constant([[0.7,0.5]]) #w为待优化的权重 #其中,stddev为标准差,seed为随机种子 w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1)) w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1)) #将每层输入乘以权重进行矩阵乘法,得到输出y a=tf.matmul(x,w1) y=tf.matmul(a,w2) with tf.Session() as sess: init_op=tf.global_variables_initializer() #在sess.run中写入init_op实现对于所有变量的初始化 sess.run(init_op) #计算图运算,输出结果 print(sess.run(y))
EX2:
import tensorflow as tf #tf.placeholder给输入占位,以便一次喂入一组或者多组数据 x=tf.placeholder(tf.float32,shape=(1,2)) w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1)) w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1)) #前向传播 a=tf.matmul(x,w1) y=tf.matmul(a,w2) with tf.Session() as sess: init_op=tf.global_variables_initializer() sess.run(init_op) print(sess.run(y,feed_dict={x:[[0.7,0.5]]}))#,feed_dict喂数据
EX3:
import tensorflow as tf x=tf.placeholder(tf.float32,shape=(None,2)) w1=tf.Variable(tf.random_normal([2,3],stddev=1,seed=1)) w2=tf.Variable(tf.random_normal([3,1],stddev=1,seed=1)) a=tf.matmul(x,w1) y=tf.matmul(a,w2) with tf.Session() as sess: init_op=tf.global_variables_initializer() sess.run(init_op) print(sess.run(y,feed_dict={x:[[0.7,0.5],[0.2,0.3],[0.3,0.4],[0.4,0.5]]})) print(sess.run(w1)) print(sess.run(w2))
-
@xuxiaohao 建议尝试不用深度学习框架,只用numpy实现神经网络的前向传播和反向传播
-
@zkhust 谢谢学长!那我去学习一下numpy!
-
深度学习算法学习
神经网络前向传播递推矩阵递推公式(推导练习,加深对深度学习理解)
【温故知新】:-
神经元可以看做一个函数
-
函数的梯度反映的是函数的最陡增长方向
-
代价函数是以bias和weight为输入,大量带标记训练数据集为参数,以一个代价数为输出的函数
-
梯度下降算法首先计算梯度值,然后每次沿着梯度向量的反方向行走一小步 ,不断重复可以收敛。
-
梯度向量的相反数告诉我们如何微调权重偏置的值。变动大小与 |现值-目标值| 成正比。
-
反向传播算法算的是单个训练样本想怎样修改权重与偏置,不仅是说每个参数应该变大还是变小,还包括了每个参数应该变大还是变小,才能够最快地降低代价。
-
反向传播算法的微积分原理:
如图:计算代价函数对于权重的敏感程度计算公式
-
-
深度学习反向传播算法学习
- 反向传播,用于训练模型参数,在所有参数上采用梯度下降,使得NN模型在训练数据上的损失函数最小
- 损失函数,是预测值与已知答案的差距
- 采用sigmoid等激励函数是为了当权重与偏置有一定改变时,损失函数的变化较小(相比较,感知器的激活函数则是一个阶跃函数,损失函数的会因为权重的微小变化而发生突变)。
- 学习率,决定了参数每一次更新的幅度。
反向传播算法的方法:
1.将输出层的误差按权重分配,反向传播给隐藏层
2.链式求导,根据求得的误差来求各个误差值对权重的偏导
:
其中:
3.将计算所得的偏导值代入梯度下降公式中,进一步对于每一层的参数进行更新。
敲重点
经典书籍《神经网络与深度学习》中对于delta的描述为在第l层第j个神经元上的误差,定义为误差对于当前带权输入求偏导,公式如下:
反向传播4大公式(矩阵化后便于利用矩阵乘法编程实现)
(看了一下Stanford上面的CS229的note和problem set,感觉自己看的吴恩达机器学习CS229的版本简单好多啊)
-
用numpy实现最简单的NN
写了一个没有bias,没有正则化,没有很多隐藏层的NN,
后续不断优化吧。。
(bug:一开始写了一个有问题的输入,导致输入矩阵不可逆,出现了函数没法收敛问题。)#-*- coding:utf-8 -*- import numpy as np #将变量映射到(0,1)区间 def sigmoid(x): return 1/(np.exp(-x)+1) def deriv(x): return x*(1-x) #输入数据 x=np.array([[0,0,1], [0,1,1], [1,0,1], [1,1,1]]) #输出数据 y=np.array([[0], [1], [1], [0]]) #初始化随机种子,保证每一次生成的随机数相同 np.random.seed(1) #权重随机初始化 w0=2*np.random.random((3,4))-1 w1=2*np.random.random((4,1))-1 #训练 for j in range(60000): #正向传播 a0=x a1=sigmoid(np.dot(a0,w0)) a2=sigmoid(np.dot(a1,w1)) a2_error=(y-a2) if(j%10000)==0: print("Error:"+str(np.mean(np.abs(a2_error)))) #反向传播误差值 a2_delta=a2_error*deriv(a2) a1_error=a2_delta.dot(w1.T) a1_delta=a1_error*deriv(a1) #梯度下降更新权值 w1+=(a1.T).dot(a2_delta) w0+=(a0.T).dot(a1_delta)
误差收敛情况:
Error:0.4964100319027255 Error:0.008584525653247157 Error:0.005789459862507806 Error:0.004629176776769983 Error:0.003958765280273646 Error:0.0035101225678616736
-
NUMPY学习
(跟着教程走了一遍NUMPY的基本语法,待日后方便查询。。。)
#NUMPY ARRAY BASIC import numpy as np ###########################3 #part1:basis ############################ a=np.array([[1,2],[0,3]],dtype=np.int64) a.dtype#dtype=np.int64 a.dtype.name#int64 a.size(4) a.shape#(2,2) a.ndim#dimension 2 np.zeros((2,3))#all 0s np.ones(((3,4))#all 1s np.empty((4,5))#all numbers->0 np.arange(12).reshape((3,4))#generate numbers ranging from 0-11 #and shape is (3,4) np.arange(10,20,2)#step is 2 np.linspace(1,10,20)#cut a line into 20 parts np.linspace(1,10,2).reshape(2,1)#change the vector into matrix ############################ #part2:calculations1 ########################### c=b**2#c=b^2 b=np.array(4),print(b==3) #output:[False,False,False,True] c=a*b#output,ci=ai*bin np.dot(a,b)#matrix multi <=>a.dot(b) ######################### #part3:random number ######################### a=np.random.random((2,4))#generate a (2,4) matrix whose values are in (0,1) np.max(a) np.min(a) np.sum(a) np.max(a,axis=0)#find max in rows np.min(a,axis=1)#find min in cals ######################### #part4:calculations2 #################### A=np.arange(2,14).reshape((2,6)) indexOfMin=np.argmin(A) np.mean(A)#average1 np.average(A)#average np.median(A)#zhong wei shu C=np.cumsum(A)#C[0]=A[i],C[i+1]=C[0]+A[i+1] D=np.diff(A)#D[i+1]=A[i+1]-A[i] np.nonzero(A)#find nonzero numbers np.sort(A)#sort for each rows np.transpose(A)#A.T (A.T).dot(A)=E np.clip(A,a_min,a_max)#{all numbers:<a_min}:=a_min,{all numbers:>a_max}:=a_max np.mean(A,axis=0) ############################ #part5:Index ############################# a[2] a[2,1]<=>a[2][1] a[2,:]# row vector 2 a[:,1]# cal vector 1 a[1,1:2]# number in row vector 1 and(cal index ranging from [1,2)) for row in A: print(row)#output its rows for col in A.T: print(col)#output its columns A.flatten()#change A into one dimension list for item in A.flat:#A.flat is a iteration ############################## #part7:Emerge ############################### A=np.array([1,1,1]) B=np.array([2,2,2]) np.vstack((A,B))# vertical stack np.hstack((A,B)) #horizontal stack,out put:[1 1 1 2 2 2] A[np.newaxis,:] #add a new dimension in front of original dimensions C=np.concatenate((A,A,B,B),axis=0)#Multi-Matrix emerge in the vertical axis ########################################## #part8: Split ########################################### A=np.arange(12).reshape(3,4) np.split(A,2,axis=1)#split the array into equal arrays np.array_split(A,3,axis=1)#unequal arrays np.vsplit(A,3) #vertical split np.hsplit(A,2) #horizontal split ########################## #copy&deep copy ########################## a=np.arange(4)#array([0,1,2,3]) b=a#IN NUMPY b<=>a,when a[0]:=11,b[0]turns into 11! b is a# output:Ture b=a.cpoy#only copy numbers->deep copy b is a#output False
-
PANDAS学习(1)
(大好时光,不如刷刷熊猫)#Series,一位数组,与numpy的array相类似 In [6]: s=pd.Series([1,3,6,np.nan,5,6]) In [7]: s Out[7]: 0 1.0 1 3.0 2 6.0 3 NaN 4 5.0 5 6.0 dtype: float64 #DataFrame,二维的表格型数据结构,每一个坐标轴都有自己的标签。是series的字典项。 In [19]: df=pd.DataFrame(np.random.randn(6,4),index=dates,columns=['a','b','c','d']) #index->hang suo ying ,columns->lie suoying In [20]: df Out[20]: a b c d 2016-01-01 1.083966 -1.131710 0.515652 0.837967 2016-01-02 0.950895 -0.100363 0.247957 0.753589 2016-01-03 0.370636 0.375547 -1.069627 1.738645 2016-01-04 -0.726578 1.390678 -0.309058 0.495773 2016-01-05 0.869181 -0.497488 0.550426 -0.928189 2016-01-06 1.330088 0.252316 0.272717 -1.151035 In [22]: df1=pd.DataFrame(np.arange(12).reshape((3,4))) In [23]: df1 Out[23]: 0 1 2 3 0 0 1 2 3 1 4 5 6 7 2 8 9 10 11 In [9]: df2=pd.DataFrame({'A':[1.], ...: 'B':['C']}) In [10]: df2 Out[10]: A B 0 1.0 C In [15]: df2=pd.DataFrame({'A':np.arange(4), ...: 'B':pd.Categorical(["test","train","test","train"])}) In [16]: df2 Out[16]: A B 0 0 test 1 1 train 2 2 test 3 3 train #得到DataFrame的各列数据类型 In [19]: df2.dtypes Out[19]: A int64 B category dtype: object #列索引.index In [20]: df2.index Out[20]: RangeIndex(start=0, stop=4, step=1) #行索引.column In [21]: df2.columns Out[21]: Index(['A', 'B'], dtype='object') #DataFrame的数据部分.values In [23]: c=df2.values In [24]: c Out[24]: array([[0, 'test'], [1, 'train'], [2, 'test'], [3, 'train']], dtype=object) #.describe()可以做一些number的分析,如个数、平均值、方差等。 In [25]: df2.describe() Out[25]: A count 4.000000 mean 1.500000 std 1.290994 min 0.000000 25% 0.750000 50% 1.500000 75% 2.250000 max 3.000000 #看做矩阵,.T求转置 In [26]: df2.T Out[26]: 0 1 2 3 A 0 1 2 3 B test train test train #将行或者列(axis=0)进行升或降(ascending=False)序排列 In [31]: df2.sort_index(axis=0,ascending=False) Out[31]: A B 3 3 train 2 2 test 1 1 train 0 0 test Out[33]: A B 0 0 test 1 1 train 2 2 test 3 3 train #将某个索引下的values进行排序 In [34]: df2.sort_values(by='B') Out[34]: A B 0 0 test 2 2 test 1 1 train 3 3 train
-
Sklearn.datasets探索
1.boston数据集适合于Regression训练
1 from sklearn.datasets import load_boston 2 import numpy as np 3 boston=load_boston() 4 print(boston.data.shape) (506, 13)
2.Iris数据集适合于multi-classifier训练
In [12]: from sklearn.datasets import load_iris In [13]: iris=load_iris() In [14]: print(iris.data.shape) (150, 4) In [15]: print(iris.target.shape) (150,) In [16]: list(iris.target_names) Out[16]: ['setosa', 'versicolor', 'virginica'] In [20]: data,target=load_iris(return_X_y=True) In [21]: print(data.shape) (150, 4) In [22]: print(target.shape) (150,)
3.digits手写数字数据集(8*8)
+用matplotlib画图并保存图像Linux由于没有GUI,所以要以下面的方式导入matplotlib.pyplot
import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt
以matplotlib.pyplot.savefig( )函数保存图片后查看
In [1]: from sklearn.datasets import load_digits In [2]: digits=load_digits() In [3]: print(digits.data.shape) (1797, 64) In [4]: print(digits.target.shape) (1797,) In [5]: print(digits.images.shape) (1797, 8, 8) In [6]: import matplotlib In [8]: matplotlib.use('Agg') In [9]: import matplotlib.pyplot as plt In [10]: plt.matshow(digits.images[0]) Out[10]: <matplotlib.image.AxesImage at 0x7ff5dce8c518> In [11]: plt.show() /home/xxh/.local/lib/python3.7/site-packages/matplotlib/figure.py:445: UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure. % get_backend()) In [12]: plt.savefig('/home/xxh/tf/1.png')
-
KNN
-
K-近邻是聚类的一种算法,用于数据分类。
-
KNN算法主要步骤
1)计算测试数据与各个训练数据之间距离
(一般使用欧氏距离或曼哈顿距离)
2)按距离的递增关系进行排序
3)选取距离最小的K个点
4)确定前K个点所在类别的出现频率
5)返回前K个点中出现频率最高的类别作为测试数据的预测分类
from numpy import * import operator def createDataSet(): data=array([[1.0,1.1],[1.0,0.9],[0.0,0.1],[0,0.1]]) target=['A','A','B','B'] return data,target def classify(test,data,target,k): datasize=data.shape[0] diff=tile(test,(datasize,1))-data#tile(,):test按照(x,y)方向复制datasize和1遍 sq_diff=diff**2 sq_dis=sq_diff.sum(axis=1) dis=sq_dis**0.5 sorted_dis_index=dis.argsort()#argsort()得出索引排序结果,升序 cnt={} for i in range(k): num=target[sorted_dis_index[i]] cnt[num]=cnt.get(num,0)+1#.get() 返回cnt[num]的值(如果 cnt[num]不存在,初始化cnt[num]=0) sorted_cnt=sorted(cnt.items(),key=operator.itemgetter(1),reverse=True)#operator.itemgetter(1),获取对象的第1个域的值 return sorted_cnt[0][0] data,target=createDataSet() print(classify([1,1],data,target,3))
KNN算法的缺陷
(1) 样本不均衡
采用权值的方法来改进。和该样本距离小的邻居权值大,和该样本距离大的邻居权值则相对较小
(2) 计算非常耗时。为了提高kNN搜索的效率,可以考虑使用特殊的结构存储训练数据,以减小计算距离的次数。Solution:K Dimension Tree
- kd树是是一种二叉树,表示对k维空间的一个划分,构造kd树相当于不断地用垂直于坐标轴的超平面将K维空间切分,构成一系列的K维超矩形区域。kd树的每个结点对应于一个k维超矩形区域。利用kd树可以省去对大部分数据点的搜索,从而减少搜索的计算量。
-
-
机器学习实战--KNN分类器
1.KNN聚类算法from numpy import * import operator def classify(test,data,target,k): datasize=data.shape[0] diff=tile(test,(datasize,1))-data#tile() sq_diff=diff**2 sq_dis=sq_diff.sum(axis=1) dis=sq_dis**0.5 sorted_dis_index=dis.argsort() cnt={} for i in range(k): num=target[sorted_dis_index[i]] cnt[num]=cnt.get(num,0)+1#get() return value of cnt[num](if cnt[num] doesn't exist cnt[num]=0) sorted_cnt=sorted(cnt.items(),key=operator.itemgetter(1),reverse=True)#itemgetter(1) return sorted_cnt[0][0] #data,target=createDataSet() #print(classify([1,1],data,target,3))
2.文件转矩阵形式
def file2matrix(filename): f=open(filename) array_line=f.readlines() len_line=len(array_line) data=zeros((len_line,3)) tar=[] index=0 for line in array_line: line=line.strip() line2list=line.split('\t') data[index,:]=line2list[0:3] tar.append(int(line2list[-1])) index+=1 return data,tar dt,tar=file2matrix('datingTestSet2.txt') #print(dt) #print(tar)
3.作图观察数据集两列特征值之间的关系
import matplotlib as mlp mlp.use('Agg') import matplotlib.pyplot as plt fig=plt.figure() ax=fig.add_subplot(111) ax.scatter(dt[:,1],dt[:,2],15.0*array(tar),15.0*array(tar)) #plt.savefig('/home/xxh/tf/KNN/datingTestPic.png')
得到散点图:
3.数据归一化
def autoNorm(dataset): minval=dataset.min(0) maxval=dataset.max(0) Range=maxval-minval normdataset=zeros(shape(dataset)) m=dataset.shape[0] normdataset=dataset-tile(minval,(m,1)) normdataset=normdataset/tile(Range,(m,1)) return normdataset,Range,minval #normdt,range,minval=autoNorm(dt) #print(normdt) #print(range) #print(minval)
4.分类器测试(主函数)
def datingClassTest(): errorList=[] ratioList=[] data,target=file2matrix('datingTestSet2.txt') normdata,ranges,minval=autoNorm(data) m=normdata.shape[0] for j in range(1,100): ratioOfTrainingData=0.01*j ratioList.append(ratioOfTrainingData) numOfTrainingData=int(m*ratioOfTrainingData) errorNum=0.0 for i in range(numOfTrainingData): result=classify(normdata[i,:],normdata[numOfTrainingData:m,:],target[numOfTrainingData:m],3) if(result!=target[i]):errorNum+=1.0 errorRate=errorNum/float(numOfTrainingData) print(j,end=' ') print(errorRate) errorList.append(float(errorRate)) figure=plt.figure() axx=figure.add_subplot(111) axx.scatter(ratioList[:],errorList[:]) plt.savefig('/home/xxh/tf/KNN/KNN_TEST.png') datingClassTest()
顺便画了一下测试集比例与准确率之间的关系图:
5.分类器使用def classifyPerson(): resultList=['not at all','in small doses','in large doses'] percent=float(input("percentage")) ffm=float(input("frequence")) icecream=float(input("ice-cream")) data,target=file2matrix('datingTestSet2.txt') normdata,ranges,minval=autoNorm(data) inArr=array([ffm,percent,icecream]) result=classify((inArr-minval)/ranges,normdata,target,3) print(resultList[result-1]) classifyPerson()
-
机器学习实战——KNN手写数字识别
from numpy import* from os import listdir import operator
1.基于KNN的分类器
def classify(test,data,target,k): datasize=data.shape[0] diff=tile(test,(datasize,1))-data#tile(扩展行,扩展列) sq_diff=diff**2 sq_dis=sq_diff.sum(axis=1)#axis=1->求列的和;axis=0->求行的和 dis=sq_dis**0.5 sorted_dis_index=dis.argsort() cnt={} for i in range(k): num=target[sorted_dis_index[i]] cnt[num]=cnt.get(num,0)+1 sorted_cnt=sorted(cnt.items(),key=operator.itemgetter(1),reverse=True)#itemgetter(1) :0->index,1->key return sorted_cnt[0][0] #data,target=createDataSet() #print(classify([1,1],data,target,3))
2.图片转向量
def img2vec(filename): returnVec=zeros((1,1024)) fr=open(filename) for i in range(32): lineStr=fr.readline() for j in range(32): returnVec[0,32*i+j]=int(lineStr[j]) return returnVec #testVector=img2vec("0_0.txt")
3.手写数字识别主函数
def digitRecognition(): hwLabels=[] dataFileList=listdir('trainingDigits') len_fileList=len(dataFileList) data=zeros((len_fileList,1024)) for i in range(len_fileList): fileNameStr=dataFileList[i] fileStr=fileNameStr.split(',')[0] classNumStr=int(fileStr.split('_')[0]) hwLabels.append(classNumStr) data[i,:]=img2vec('trainingDigits/%s'% fileNameStr) testFileList=listdir('testDigits') errorCnt=0.0 len_testList=len(testFileList) for i in range(len_testList): fileNameStr=testFileList[i] fileStr=fileNameStr.split(',')[0] classNumStr=int(fileStr.split('_')[0]) testVector=img2vec('testDigits/%s'%fileNameStr) classifierResult=classify(testVector,data,hwLabels,3) print("classifier: %d, right: %d" %(classifierResult ,classNumStr)) if( classifierResult != classNumStr ): errorCnt+=1.0 errorRate=(errorCnt/float(len_testList)) #print(len_testList) print(errorCnt) print(errorRate)
4.测试结果:
(好慢啊)#errorCnt:11.0 #errorRate:0.011627906976744186 #timeCost:19.133 seconds