一个少数服从多数的投票模型,可以用在多分类的情况。
算法描述:
KNN是根据点与点之间的关系来进行判断,所以有些噪声可能会对结果有些影响。还有KNN并不需要训练,但需要遍历整个训练集,所以预测会比较慢。
np.linalg.norm(a-b) #欧氏距离
np.dot(a,b) #按照矩阵乘法规则来运算
-----------------------------------------------------------------------------------------------------------------------------------------------
更详细参见文章
http://blog.csdn.net/yan456jie/article/details/52074141
http://www.cnblogs.com/v-July-v/archive/2012/11/20/3125419.html
是对数据点在k维空间(如二维(x,y),三维(x,y,z),k维(x1,y,z..))中划分的一种数据结构,主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索)。就是把整个空间划分为特定的几个部分,然后在特定空间的部分内进行相关搜索操作。
6个二维数据点{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)}构建kd树的具体步骤为:
代码:
class KD_node:
def __init__(self,elt=None,split=None,LL=None,RR=None):
"""
elt:样本点,即根节点
split:划分域
LL,RR:左右子空间内数据点构成的kd-tree
"""
self.elt = elt
self.split = split
self.left = LL
self.right = RR
(基于方差的选择方法)尽可能将相似的点放在一颗子树里面,所以kd-tree采取的思想就是计算所有数据点在每个维度上的数值的方差,然后方差最大的维度就作为当前节点的划分维度。
代码:
def computeVariance(arr):
"""
var = E[X^2] - (E(X))^2
"""
sum1 = sum(arr)
mean = sum1/arr.size
arr2 = arr * arr #list不能相乘
sum2 = sum(arr2)
return sum2/arr.size - mean ** 2
代码:
def createKDTree(root,data_list):
"""
root:当前树的根节点
data_list:数据点的集合(无序)
return:构造的KDTree的树根
LEN:数据点的个数
demension:数据点的维数
"""
if len(data_list) == 0:
return
LEN = len(data_list)
demension = len(data_list[0])
var_max = 0
split = 0
for d in range(demension):
arr1 = np.array(demension)[:,d]
var = computeVariance(arr1)
#找出方差最大的那一维,记为split
if var_max < var:
var_max = var
split = d
#根据选择的划分域对数据点进行排序,方便分配左右儿子
data_list = sorted(data_list,key = lambda x:x[split])
elt = data_list[LEN//2]
root = KD_node(elt,split)
root.left = createKDTree(root.left,data_list[:LEN//2])
root.right = createKDTree(root.right,data_list[LEN//2+1:])
return root
1.二叉查找:
从根节点开始进行查找,直到叶子节点;在这个过程中,记录最短的距离,和对应的数据点;同时维护一个栈,用来存储经过的节点
2.回溯查找:
通过计算查找点到分割平面的距离(这个距离比较的是分割维度上的值的差,并不是分割节点到分割平面上的距离,虽然两者的值是相等的)与当前最短距离进行比较,决定是否需要进入节点的相邻子空间进行查找
e.g
已知:
步骤:
1)首先扫描到叶子节点,扫描过程中记录的最近点为p(5,4),最短距离为d;
2)现在开始回溯,假设分割的维度为ss,其实回溯的过程就是确定是否有必要进入相邻子空间进行搜索,确定的依据就是当前点到最近点的距离d是否大于当前点到分割面(在二维空间中实际上就是一条线)的距离L,如果d < L,那么说明完全没有必要进入到另一个子空间进行搜索,直接继续向上一层回溯;如果有d > L,那么说明相邻子空间中可能有距查询点更近的点。
代码:
def findNN(root,query):
"""
root:KDTree的树根
query:查询点
return:返回距离data最近的点NN,同时返回最短距离min_dist
nodeList:用来存储二分查找经过的节点,先进后出,方便回溯查找
back_elt:回溯查找找弹出的节点
ss:分割的维度
"""
NN = root.elt
min_dist = np.linalg.norm(np.array(NN)-np.array(query))
nodeList = []
temp_root = root
#二叉查找,直到叶子节点
while temp_root:
nodeList.append(temp_root)
dist = np.linalg.norm(np.array(temp_root.elt)-np.array(query))
if dist < min_dist:
NN = temp_root.elt
min_dist = dist
#当前节点的划分域
ss = temp_root.split
if query[ss] < temp_root[ss]:
temp_root = temp_root.left
else:
temp_root = temp_root.right
#回溯查找,将nodeList遍历一遍
while nodeList:
back_root = nodeList.pop()
back_elt = back_root.elt
ss = back_root.split
"""
if min大于query到分割面的距离:
相邻子空间可能存在更近的点
"""
if abs(query[ss] - back_elt[ss]) < min_dist:
if query[ss] > back_elt[ss]:
temp_root = back_root.left
else:
temp_root = back_root.right
#类似二分查找
if temp_root:
nodeList.append(temp_root)
#相邻子空间找更近的点
dist = np.linalg.norm(np.array(temp_root.elt)-np.array(query))
if dist < min_dist:
NN = temp_root.elt
min_dist = dist
return NN,min_dist