Python语言描述KNN算法与Kd树

最近邻法和k-近邻法

下面图片中只有三种豆,有三个豆是未知的种类,如何判定他们的种类?

提供一种思路,即:未知的豆离哪种豆最近就认为未知豆和该豆是同一种类。由此,我们引出最近邻算法的定义:为了判定未知样本的类别,以全部训练样本作为代表点,计算未知样本与所有训练样本的距离,并以最近邻者的类别作为决策未知样本类别的唯一依据。但是,最近邻算法明显是存在缺陷的,比如下面的例子:有一个未知形状(图中绿色的圆点),如何判断它是什么形状?

显然,最近邻算法的缺陷——对噪声数据过于敏感,为了解决这个问题,我们可以可以把未知样本周边的多个最近样本计算在内,扩大参与决策的样本量,以避免个别数据直接决定决策结果。由此,我们引进K-最近邻算法。K-最近邻算法是最近邻算法的一个延伸。基本思路是:选择未知样本一定范围内确定个数的K个样本,该K个样本大多数属于某一类型,则未知样本判定为该类型。如何选择一个最佳的K值取决于数据。一般情况下,在分类时较大的K值能够减小噪声的影响,但会使类别之间的界限变得模糊。待测样本(绿色圆圈)既可能分到红色三角形类,也可能分到蓝色正方形类。如果k取3,从图可见,待测样本的3个邻居在实线的内圆里,按多数投票结果,它属于红色三角形类。但是如果k取5,那么待测样本的最邻近的5个样本在虚线的圆里,按表决法,它又属于蓝色正方形类。在实际应用中,K先取一个比较小的数值,再采用交叉验证法来逐步调整K值,最终选择适合该样本的最优的K值。

KNN算法实现 
算法基本步骤:

1)计算待分类点与已知类别的点之间的距离

2)按照距离递增次序排序

3)选取与待分类点距离最小的k个点

4)确定前k个点所在类别的出现次数

5)返回前k个点出现次数最高的类别作为待分类点的预测分类

  下面是一个按照算法基本步骤用python实现的简单例子,根据已分类的4个样本点来预测未知点(图中的灰点)的分类:

from numpy import * 

# create a dataset which contains 4 samples with 2 classes
def createDataSet():
  # create a matrix: each row as a sample
  group = array([[1.0, 0.9], [1.0, 1.0], [0.1, 0.2], [0.0, 0.1]])
  labels = ['A', 'A', 'B', 'B'] # four samples and two classes
  return group, labels
# classify using kNN (k Nearest Neighbors )
# Input:   newInput: 1 x N
#       dataSet: M x N (M samples N, features)
#       labels:  1 x M
#       k: number of neighbors to use for comparison
# Output:   the most popular class label
def kNNClassify(newInput, dataSet, labels, k):
  numSamples = dataSet.shape[0] # shape[0] stands for the num of row
  ## step 1: calculate Euclidean distance
  # tile(A, reps): Construct an array by repeating A reps times
  # the following copy numSamples rows for dataSet
  diff = tile(newInput, (numSamples, 1)) - dataSet # Subtract element-wise
  squaredDiff = diff ** 2 # squared for the subtract
  squaredDist = sum(squaredDiff, axis = 1) # sum is performed by row
  distance = squaredDist ** 0.5
  ## step 2: sort the distance
  # argsort() returns the indices that would sort an array in a ascending order
  sortedDistIndices = argsort(distance)
  classCount = {} # define a dictionary (can be append element)
  for i in xrange(k):
    ## step 3: choose the min k distance
    voteLabel = labels[sortedDistIndices[i]]
    ## step 4: count the times labels occur
    # when the key voteLabel is not in dictionary classCount, get()
    # will return 0
    classCount[voteLabel] = classCount.get(voteLabel, 0) + 1
  ## step 5: the max voted class will return
  maxCount = 0
  for key, value in classCount.items():
    if value > maxCount:
      maxCount = value
      maxIndex = key
  return maxIndex
  if __name__== "__main__":
  dataSet, labels = createDataSet()
  testX = array([1.2, 1.0])
  k = 3
  outputLabel = kNNClassify(testX, dataSet, labels, 3)
  print "Your input is:", testX, "and classified to class: ", outputLabel
  testX = array([0.1, 0.3])
  outputLabel = kNNClassify(testX, dataSet, labels, 3)
  print "Your input is:", testX, "and classified to class: ", outputLabel

结果如下:
Your input is: [ 1.2 1. ] and classified to class: A
Your input is: [ 0.1 0.3] and classified to class: B

  OpenCV中也提供了机器学习的相关算法,其中KNN算法的最基本例子如下

import numpy as np
import matplotlib.pyplot as plt
import cv2
# Feature set containing (x,y) values of 25 known/training data
trainData = np.random.randint(0,100,(25,2)).astype(np.float32)
# Labels each one either Red or Blue with numbers 0 and 1
responses = np.random.randint(0,2,(25,1)).astype(np.float32)
# Take Red families and plot them
red = trainData[responses.ravel()==0]
plt.scatter(red[:,0],red[:,1],80,'r','^')
# Take Blue families and plot them
blue = trainData[responses.ravel()==1]
plt.scatter(blue[:,0],blue[:,1],80,'b','s')
# Testing data
newcomer = np.random.randint(0,100,(1,2)).astype(np.float32)
plt.scatter(newcomer[:,0],newcomer[:,1],80,'g','o')
knn = cv2.KNearest()
knn.train(trainData,responses) # Trains the model
# Finds the neighbors and predicts responses for input vectors.
ret, results, neighbours ,dist = knn.find_nearest(newcomer, 3)
print "result: ", results,"\n"
print "neighbours: ", neighbours,"\n"
print "distance: ", dist
plt.show()

>>>
result: [[ 0.]]
neighbours: [[ 0. 0. 0.]]
distance: [[ 65. 145. 178.]]

可以看到KNN算法将未知点分到第0组(红色三角形组),从上图中也可看出3个距离未知点最近的样本都属于第0组,因此算法返回分类标签也为0。

KNN算法的缺陷

观察下面的例子,我们看到对于样本X,通过KNN算法,我们显然可以得到X应属于红点,但对于样本Y,通过KNN算法我们似乎得到了Y应属于蓝点的结论,而这个结论直观来看并没有说服力。

由上面的例子可见:该算法在分类时有个重要的不足是,当样本不平衡时,即:一个类的样本容量很大,而其他类样本数量很小时,很有可能导致当输入一个未知样本时,该样本的K个邻居中大数量类的样本占多数。 但是这类样本并不接近目标样本,而数量小的这类样本很靠近目标样本。这个时候,我们有理由认为该位置样本属于数量小的样本所属的一类,但是,KNN却不关心这个问题,它只关心哪类样本的数量最多,而不去把距离远近考虑在内,因此,我们可以采用权值的方法来改进。和该样本距离小的邻居权值大,和该样本距离大的邻居权值则相对较小,由此,将距离远近的因素也考虑在内,避免因一个样本过大导致误判的情况。

  从算法实现的过程可以发现,该算法存两个严重的问题,第一个是需要存储全部的训练样本,第二个是计算量较大,因为对每一个待分类的样本都要计算它到全体已知样本的距离,才能求得它的K个最近邻点。KNN算法的改进方法之一是分组快速搜索近邻法。其基本思想是:将样本集按近邻关系分解成组,给出每组质心的位置,以质心作为代表点,和未知样本计算距离,选出距离最近的一个或若干个组,再在组的范围内应用一般的KNN算法。由于并不是将未知样本与所有样本计算距离,故该改进算法可以减少计算量,但并不能减少存储量。

KD树

  实现k近邻法时,主要考虑的问题是如何对训练数据进行快速k近邻搜索。这在特征空间的维数大及训练数据容量大时尤其必要。k近邻法最简单的实现是线性扫描(穷举搜索),即要计算输入实例与每一个训练实例的距离。计算并存储好以后,再查找K近邻。当训练集很大时,计算非常耗时。为了提高kNN搜索的效率,可以考虑使用特殊的结构存储训练数据,以减小计算距离的次数。

  kd树(K-dimension tree)是一种对k维空间中的实例点进行存储以便对其进行快速检索的树形数据结构。kd树是是一种二叉树,表示对k维空间的一个划分,构造kd树相当于不断地用垂直于坐标轴的超平面将K维空间切分,构成一系列的K维超矩形区域。kd树的每个结点对应于一个k维超矩形区域。利用kd树可以省去对大部分数据点的搜索,从而减少搜索的计算量。

对一个三维空间,kd树按照一定的划分规则把这个三维空间划分了多个空间,如下图所示

类比“二分查找”:给出一组数据:[9 1 4 7 2 5 0 3 8],要查找8。如果挨个查找(线性扫描),那么将会把数据集都遍历一遍。而如果排一下序那数据集就变成了:[0 1 2 3 4 5 6 7 8 9],按前一种方式我们进行了很多没有必要的查找,现在如果我们以5为分界点,那么数据集就被划分为了左右两个“簇” [0 1 2 3 4]和[6 7 8 9]。因此,根本久没有必要进入第一个簇,可以直接进入第二个簇进行查找。把二分查找中的数据点换成k维数据点,这样的划分就变成了用超平面对k维空间的划分。空间划分就是对数据点进行分类,“挨得近”的数据点就在一个空间里面。

  构造kd树的方法如下:构造根结点,使根结点对应于K维空间中包含所有实例点的超矩形区域;通过下面的递归的方法,不断地对k维空间进行切分,生成子结点。在超矩形区域上选择一个坐标轴和在此坐标轴上的一个切分点,确定一个超平面,这个超平面通过选定的切分点并垂直于选定的坐标轴,将当前超矩形区域切分为左右两个子区域(子结点);这时,实例被分到两个子区域,这个过程直到子区域内没有实例时终止(终止时的结点为叶结点)。在此过程中,将实例保存在相应的结点上。通常,循环的择坐标轴对空间切分,选择训练实例点在坐标轴上的中位数为切分点,这样得到的kd树是平衡的(平衡二叉树:它是一棵空树,或其左子树和右子树的深度之差的绝对值不超过1,且它的左子树和右子树都是平衡二叉树)。 

  KD树中每个节点是一个向量,和二叉树按照数的大小划分不同的是,KD树每层需要选定向量中的某一维,然后根据这一维按左小右大的方式划分数据。在构建KD树时,关键需要解决2个问题:(1)选择向量的哪一维进行划分;(2)如何划分数据。第一个问题简单的解决方法可以是选择随机选择某一维或按顺序选择,但是更好的方法应该是在数据比较分散的那一维进行划分(分散的程度可以根据方差来衡量)。好的划分方法可以使构建的树比较平衡,可以每次选择中位数来进行划分,这样问题2也得到了解决。

  构造平衡kd树算法:

输入:kk维空间数据集T={x1,x2,...,xN},其中

输出:kd树

(1)开始:构造根结点,根结点对应于包含T的k维空间的超矩形区域。选择x(1)x(1)为坐标轴,以T中所有实例的x(1)x(1)坐标的中位数为切分点,将根结点对应的超矩形区域切分为两个子区域。切分由通过切分点并与坐标轴x(1)x(1)垂直的超平面实现。由根结点生成深度为1的左、右子结点:左子结点对应坐标x(1)x(1)小于切分点的子区域,右子结点对应于坐标x(1)x(1)大于切分点的子区域。将落在切分超平面上的实例点保存在根结点。

(2)重复。对深度为j的结点,选择x(l)x(l)为切分的坐标轴,l=j%k+1l=j%k+1,以该结点的区域中所有实例的x(l)x(l)坐标的中位数为切分点,将该结点对应的超矩形区域切分为两个子区域。切分由通过切分点并与坐标轴x(l)x(l)垂直的超平面实现。由该结点生成深度为j+1的左、右子结点:左子结点对应坐标x(l)x(l)小于切分点的子区域,右子结点对应坐标x(l)x(l)大于切分点的子区域。将落在切分超平面上的实例点保存在该结点。

  下面用一个简单的2维平面上的例子来进行说明。

  例. 给定一个二维空间数据集:T={(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)}T={(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)},构造一个平衡kd树。

  解:根结点对应包含数据集T的矩形,选择x(1)x(1)轴,6个数据点的x(1)x(1)坐标中位数是6,这里选最接近的(7,2)点,以平面x(1)=7x(1)=7将空间分为左、右两个子矩形(子结点);接着左矩形以x(2)=4x(2)=4分为两个子矩形(左矩形中{(2,3),(5,4),(4,7)}点的x(2)x(2)坐标中位数正好为4),右矩形以x(2)=6x(2)=6分为两个子矩形,如此递归,最后得到如下图所示的特征空间划分和kd树。

下面的代码用递归的方式构建了kd树,通过前序遍历可以进行验证。这里只是简单地采用坐标轮换方式选取分割轴,为了更高效的分割空间,也可以计算所有数据点在每个维度上的数值的方差,然后选择方差最大的维度作为当前节点的划分维度。方差越大,说明这个维度上的数据越不集中(稀疏、分散),也就说明了它们就越不可能属于同一个空间,因此需要在这个维度上进行划分。

# -*- coding: utf-8 -*-
#from operator import itemgetter
import sys
reload(sys)
sys.setdefaultencoding('utf8')
# kd-tree每个结点中主要包含的数据结构如下
class KdNode(object):
  def __init__(self, dom_elt, split, left, right):
    self.dom_elt = dom_elt # k维向量节点(k维空间中的一个样本点)
    self.split = split   # 整数(进行分割维度的序号)
    self.left = left    # 该结点分割超平面左子空间构成的kd-tree
    self.right = right   # 该结点分割超平面右子空间构成的kd-tree
class KdTree(object):
  def __init__(self, data):
    k = len(data[0]) # 数据维度

    def CreateNode(split, data_set): # 按第split维划分数据集exset创建KdNode
      if not data_set:  # 数据集为空
        return None
      # key参数的值为一个函数,此函数只有一个参数且返回一个值用来进行比较
      # operator模块提供的itemgetter函数用于获取对象的哪些维的数据,参数为需要获取的数据在对象中的序号
      #data_set.sort(key=itemgetter(split)) # 按要进行分割的那一维数据排序
      data_set.sort(key=lambda x: x[split])
      split_pos = len(data_set) // 2   # //为Python中的整数除法
      median = data_set[split_pos]    # 中位数分割点
      split_next = (split + 1) % k    # cycle coordinates
      # 递归的创建kd树
      return KdNode(median, split,
             CreateNode(split_next, data_set[:split_pos]),   # 创建左子树
             CreateNode(split_next, data_set[split_pos + 1:])) # 创建右子树
    self.root = CreateNode(0, data)     # 从第0维分量开始构建kd树,返回根节点
# KDTree的前序遍历
def preorder(root):
  print root.dom_elt
  if root.left:   # 节点不为空
    preorder(root.left)
  if root.right:
    preorder(root.right)
if __name__ == "__main__":
  data = [[2,3],[5,4],[9,6],[4,7],[8,1],[7,2]]
  kd = KdTree(data)
  preorder(kd.root)

进行前序遍历(前序遍历首先访问根结点然后遍历左子树,最后遍历右子树)的结果如下,可见已经正确构建了kd树:

搜索kd树

  利用kd树可以省去对大部分数据点的搜索,从而减少搜索的计算量。下面以搜索最近邻点为例加以叙述:给定一个目标点,搜索其最近邻,首先找到包含目标点的叶节点;然后从该叶结点出发,依次回退到父结点;不断查找与目标点最近邻的结点,当确定不可能存在更近的结点时终止。这样搜索就被限制在空间的局部区域上,效率大为提高。

  用kd树的最近邻搜索:  
输入: 已构造的kd树;目标点xx;
输出:xx的最近邻。

(1) 在kd树中找出包含目标点xx的叶结点:从根结点出发,递归的向下访问kd树。若目标点当前维的坐标值小于切分点的坐标值,则移动到左子结点,否则移动到右子结点。直到子结点为叶结点为止;

(2) 以此叶结点为“当前最近点”;

(3) 递归的向上回退,在每个结点进行以下操作:

  (a) 如果该结点保存的实例点比当前最近点距目标点更近,则以该实例点为“当前最近点”;

  (b) 当前最近点一定存在于该结点一个子结点对应的区域。检查该子结点的父结点的另一个子结点对应的区域是否有更近的点。具体的,检查另一个子结点对应的区域是否与以目标点为球心、以目标点与“当前最近点”间的距离为半径的超球体相交。如果相交,可能在另一个子结点对应的区域内存在距离目标更近的点,移动到另一个子结点。接着,递归的进行最近邻搜索。如果不相交,向上回退。

(4) 当回退到根结点时,搜索结束。最后的“当前最近点”即为xx的最近邻点。

  以先前构建好的kd树为例,查找目标点(3,4.5)的最近邻点。同样先进行二叉查找,先从(7,2)查找到(5,4)节点,在进行查找时是由y = 4为分割超平面的,由于查找点为y值为4.5,因此进入右子空间查找到(4,7),形成搜索路径:(7,2)→(5,4)→(4,7),取(4,7)为当前最近邻点。以目标查找点为圆心,目标查找点到当前最近点的距离2.69为半径确定一个红色的圆。然后回溯到(5,4),计算其与查找点之间的距离为2.06,则该结点比当前最近点距目标点更近,以(5,4)为当前最近点。用同样的方法再次确定一个绿色的圆,可见该圆和y = 4超平面相交,所以需要进入(5,4)结点的另一个子空间进行查找。(2,3)结点与目标点距离为1.8,比当前最近点要更近,所以最近邻点更新为(2,3),最近距离更新为1.8,同样可以确定一个蓝色的圆。接着根据规则回退到根结点(7,2),蓝色圆与x=7的超平面不相交,因此不用进入(7,2)的右子空间进行查找。至此,搜索路径回溯完,返回最近邻点(2,3),最近距离1.8。

如果实例点是随机分布的,kd树搜索的平均计算复杂度是O(logN)O(logN),这里N是训练实例数。kd树更适用于训练实例数远大于空间维数时的k近邻搜索。当空间维数接近训练实例数时,它的效率会迅速下降,几乎接近线性扫描。

下面的代码对构建好的kd树进行搜索,寻找与目标点最近的样本点:

from math import sqrt
from collections import namedtuple
# 定义一个namedtuple,分别存放最近坐标点、最近距离和访问过的节点数
result = namedtuple("Result_tuple", "nearest_point nearest_dist nodes_visited")
def find_nearest(tree, point):
  k = len(point) # 数据维度
  def travel(kd_node, target, max_dist):
    if kd_node is None:
      return result([0] * k, float("inf"), 0) # python中用float("inf")和float("-inf")表示正负无穷
    nodes_visited = 1
    s = kd_node.split    # 进行分割的维度
    pivot = kd_node.dom_elt # 进行分割的“轴”
    if target[s] <= pivot[s]:      # 如果目标点第s维小于分割轴的对应值(目标离左子树更近)
      nearer_node = kd_node.left   # 下一个访问节点为左子树根节点
      further_node = kd_node.right  # 同时记录下右子树
    else:                # 目标离右子树更近
      nearer_node = kd_node.right  # 下一个访问节点为右子树根节点
      further_node = kd_node.left
    temp1 = travel(nearer_node, target, max_dist) # 进行遍历找到包含目标点的区域
    nearest = temp1.nearest_point    # 以此叶结点作为“当前最近点”
    dist = temp1.nearest_dist      # 更新最近距离
    nodes_visited += temp1.nodes_visited
    if dist < max_dist:
      max_dist = dist  # 最近点将在以目标点为球心,max_dist为半径的超球体内
    temp_dist = abs(pivot[s] - target[s])  # 第s维上目标点与分割超平面的距离
    if max_dist < temp_dist:        # 判断超球体是否与超平面相交
      return result(nearest, dist, nodes_visited) # 不相交则可以直接返回,不用继续判断
    #----------------------------------------------------------------------
    # 计算目标点与分割点的欧氏距离
    temp_dist = sqrt(sum((p1 - p2) ** 2 for p1, p2 in zip(pivot, target)))
    if temp_dist < dist:     # 如果“更近”
      nearest = pivot     # 更新最近点
      dist = temp_dist     # 更新最近距离
      max_dist = dist     # 更新超球体半径

    # 检查另一个子结点对应的区域是否有更近的点
    temp2 = travel(further_node, target, max_dist)
    nodes_visited += temp2.nodes_visited
    if temp2.nearest_dist < dist:    # 如果另一个子结点内存在更近距离
      nearest = temp2.nearest_point  # 更新最近点
      dist = temp2.nearest_dist    # 更新最近距离
    return result(nearest, dist, nodes_visited)
  return travel(tree.root, point, float("inf")) # 从根节点开始递归

下面结合前面写的代码来进行一下测试:

from time import clock
from random import random
# 产生一个k维随机向量,每维分量值在0~1之间
def random_point(k):
  return [random() for _ in range(k)]
 # 产生n个k维随机向量
def random_points(k, n):
  return [random_point(k) for _ in range(n)]
   if __name__ == "__main__":
  data = [[2,3],[5,4],[9,6],[4,7],[8,1],[7,2]] # samples
    kd = KdTree(data)
    ret = find_nearest(kd, [3,4.5])
  print ret
  N = 400000
  t0 = clock()
  kd2 = KdTree(random_points(3, N))      # 构建包含四十万个3维空间样本点的kd树
  ret2 = find_nearest(kd2, [0.1,0.5,0.8])   # 四十万个样本点中寻找离目标最近的点
  t1 = clock()
  print "time: ",t1-t0, "s"
  print ret2

结果如下图所示。先是测试了之前例子中距离(3,4.5)最近的点,可以看出正确返回了最近点(2,3)以及最近距离。然后随机生成了四十万个三维空间样本点,并构建kd树,然后搜索离(0.1,0.5,0.8)最近的样本点,并测试用时。为了进行对比我先是使用numpy算出全部四十万个距离后寻找最近点,结果耗时0.5s左右!!!怎么能这么快(⊙▽⊙),然后不用numpy自己在python中计算全部距离,结果耗时2s左右,还是比自己写的KD树要快得多...

可能是这种使用递归方式创建和搜索的kd树本身效率就不是很高(知乎:为什么说递归效率低?)。而且深层递归一定要尽量避免,一是不安全,容易导致栈溢出;二是调用代价高(递归函数调用的代价)。可以考虑转换为循环结构。循环结构的kd树实现参考:KDTree example in scipy

总结

以上就是本文关于Python语言描述KNN算法与Kd树的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题。如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

(0)

相关推荐

  • Python排序搜索基本算法之插入排序实例分析

    本文实例讲述了Python排序搜索基本算法之插入排序.分享给大家供大家参考,具体如下: 插入排序生活中非常常见,打扑克的时候人的本能就在用插入排序:把抽到的一张插入到手上牌的正确位置上.有两种插入排序方法,一种基于比较,另一种基于交换.代码如下: 1.基于比较的插入排序: # coding:utf-8 def insertionSort(seq): length=len(seq) for i in range(1,length): tmp=seq[i] for j in range(i,0,-1

  • Python数据结构与算法之二叉树结构定义与遍历方法详解

    本文实例讲述了Python数据结构与算法之二叉树结构定义与遍历方法.分享给大家供大家参考,具体如下: 先序遍历,中序遍历,后序遍历 ,区别在于三条核心语句的位置 层序遍历  采用队列的遍历操作第一次访问根,在访问根的左孩子,接着访问根的有孩子,然后下一层 自左向右一一访问同层的结点 # 先序遍历 # 访问结点,遍历左子树,如果左子树为空,则遍历右子树, # 如果右子树为空,则向上走到一个可以向右走的结点,继续该过程 preorder(t): if t: print t.value preorde

  • python中Apriori算法实现讲解

    本文主要给大家讲解了Apriori算法的基础知识以及Apriori算法python中的实现过程,以下是所有内容: 1. Apriori算法简介 Apriori算法是挖掘布尔关联规则频繁项集的算法.Apriori算法利用频繁项集性质的先验知识,通过逐层搜索的迭代方法,即将K-项集用于探察(k+1)项集,来穷尽数据集中的所有频繁项集.先找到频繁项集1-项集集合L1, 然后用L1找到频繁2-项集集合L2,接着用L2找L3,知道找不到频繁K-项集,找到每个Lk需要一次数据库扫描.注意:频繁项集的所有非空

  • Python数据结构与算法之图的最短路径(Dijkstra算法)完整实例

    本文实例讲述了Python数据结构与算法之图的最短路径(Dijkstra算法).分享给大家供大家参考,具体如下: # coding:utf-8 # Dijkstra算法--通过边实现松弛 # 指定一个点到其他各顶点的路径--单源最短路径 # 初始化图参数 G = {1:{1:0, 2:1, 3:12}, 2:{2:0, 3:9, 4:3}, 3:{3:0, 5:5}, 4:{3:4, 4:0, 5:13, 6:15}, 5:{5:0, 6:4}, 6:{6:0}} # 每次找到离源点最近的一个顶

  • K-近邻算法的python实现代码分享

    k-近邻算法概述: 所谓k-近邻算法KNN就是K-Nearest neighbors Algorithms的简称,它采用测量不同特征值之间的距离方法进行分类 用官方的话来说,所谓K近邻算法,即是给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例(也就是上面所说的K个邻居), 这K个实例的多数属于某个类,就把该输入实例分类到这个类中. k-近邻算法分析 优点:精度高.对异常值不敏感.无数据输入假定. 缺点:计算复杂度高.空间复杂度高. 适用数据范围:数值型和标称型 k-

  • Python排序搜索基本算法之选择排序实例分析

    本文实例讲述了Python排序搜索基本算法之选择排序.分享给大家供大家参考,具体如下: 选择排序就是第n次把序列中最小的元素排在第n的位置上,一旦排好就是该元素的绝对位置.代码如下: # coding:utf-8 def selectionSort(seq): length=len(seq) for i in range(length): mini=min(seq[i:]) if seq[i]>mini: j=seq.index(mini,i) seq[i],seq[j]=seq[j],seq[

  • Python使用三种方法实现PCA算法

    主成分分析,即Principal Component Analysis(PCA),是多元统计中的重要内容,也广泛应用于机器学习和其它领域.它的主要作用是对高维数据进行降维.PCA把原先的n个特征用数目更少的k个特征取代,新特征是旧特征的线性组合,这些线性组合最大化样本方差,尽量使新的k个特征互不相关.关于PCA的更多介绍,请参考:https://en.wikipedia.org/wiki/Principal_component_analysis. 主成分分析(PCA) vs 多元判别式分析(MD

  • Python数据结构与算法之图的基本实现及迭代器实例详解

    本文实例讲述了Python数据结构与算法之图的基本实现及迭代器.分享给大家供大家参考,具体如下: 这篇文章参考自<复杂性思考>一书的第二章,并给出这一章节里我的习题解答. (这书不到120页纸,要卖50块!!,一开始以为很厚的样子,拿回来一看,尼玛.....代码很少,给点提示,然后让读者自己思考怎么实现) 先定义顶点和边 class Vertex(object): def __init__(self, label=''): self.label = label def __repr__(sel

  • Python语言描述KNN算法与Kd树

    最近邻法和k-近邻法 下面图片中只有三种豆,有三个豆是未知的种类,如何判定他们的种类? 提供一种思路,即:未知的豆离哪种豆最近就认为未知豆和该豆是同一种类.由此,我们引出最近邻算法的定义:为了判定未知样本的类别,以全部训练样本作为代表点,计算未知样本与所有训练样本的距离,并以最近邻者的类别作为决策未知样本类别的唯一依据.但是,最近邻算法明显是存在缺陷的,比如下面的例子:有一个未知形状(图中绿色的圆点),如何判断它是什么形状? 显然,最近邻算法的缺陷--对噪声数据过于敏感,为了解决这个问题,我们可

  • Python语言描述机器学习之Logistic回归算法

    本文介绍机器学习中的Logistic回归算法,我们使用这个算法来给数据进行分类.Logistic回归算法同样是需要通过样本空间学习的监督学习算法,并且适用于数值型和标称型数据,例如,我们需要根据输入数据的特征值(数值型)的大小来判断数据是某种分类或者不是某种分类. 一.样本数据 在我们的例子中,我们有这样一些样本数据: 样本数据有3个特征值:X0X0,X1X1,X2X2 我们通过这3个特征值中的X1X1和X2X2来判断数据是否符合要求,即符合要求的为1,不符合要求的为0. 样本数据分类存放在一个

  • Python语言描述随机梯度下降法

    1.梯度下降 1)什么是梯度下降? 因为梯度下降是一种思想,没有严格的定义,所以用一个比喻来解释什么是梯度下降. 简单来说,梯度下降就是从山顶找一条最短的路走到山脚最低的地方.但是因为选择方向的原因,我们找到的的最低点可能不是真正的最低点.如图所示,黑线标注的路线所指的方向并不是真正的地方. 既然是选择一个方向下山,那么这个方向怎么选?每次该怎么走? 先说选方向,在算法中是以随机方式给出的,这也是造成有时候走不到真正最低点的原因. 如果选定了方向,以后每走一步,都是选择最陡的方向,直到最低点.

  • Python实现的knn算法示例

    本文实例讲述了Python实现的knn算法.分享给大家供大家参考,具体如下: 代码参考机器学习实战那本书: 机器学习实战 (Peter Harrington著) 中文版 机器学习实战 (Peter Harrington著) 英文原版[附源代码] 有兴趣你们可以去了解下 具体代码: # -*- coding:utf-8 -*- #! python2 ''''' @author:zhoumeixu createdate:2015年8月27日 ''' #np.zeros((4,2)) #np.zero

  • Python语言实现SIFT算法

    目录 一.什么是SIFT算法 二.准备工作 2.1 实验设备 2.2 OpenCV安装 三.实验工作 3.1 图像选择 3.2 程序实现 3.3 程序结果 本文侧重于如何使用Python语言实现SIFT算法 所有程序已打包:基于OpenCV-Python的SIFT算法的实现 一.什么是SIFT算法   SIFT,即尺度不变特征变换(Scale-invariant feature transform,SIFT),是用于图像处理领域的一种描述.这种描述具有尺度不变性,可在图像中检测出关键点,是一种局

  • Python语言描述最大连续子序列和

    求最大连续子序列的和是一个很经典很古老的面试题了,记得在刚毕业找工作面试那会也遇到过同款问题.今儿突然想起来,正好快到毕业季,又该是苦逼的应届生们各种面试的时候到了,就给写了一些小代码解决这个问题.也希望各位找工作的同志们都拿到心目中理想的offer,从此以后,战胜高富帅,赢取白富美,走上人生巅峰. 1.问题描述 假设有一数组(python里为list啦)[1,3,-3,4,-6,-1],求数组中最大连续子序列的和.例如在此数组中,最大连续子序列的和为5,即1+3+(-3)+4 = 5 2.O(

  • Python语言描述连续子数组的最大和

    题目描述 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决.但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止).你会不会被他忽悠住?(子向量的长度至少是1) 思路: 最大和连续子数组一定有如下几个特点: 1.第一个不为负数 2.如果前面数的累加值

  • Python实现基于KNN算法的笔迹识别功能详解

    本文实例讲述了Python实现基于KNN算法的笔迹识别功能.分享给大家供大家参考,具体如下: 需要用到: Numpy库 Pandas库 手写识别数据 点击此处本站下载. 数据说明: 数据共有785列,第一列为label,剩下的784列数据存储的是灰度图像(0~255)的像素值 28*28=784 KNN(K近邻算法): 从训练集中找到和新数据最接近的K条记录,根据他们的主要分类来决定新数据的类型. 这里的主要分类,可以有不同的判别依据,比如"最多","最近邻",或者

  • python K近邻算法的kd树实现

    k近邻算法的介绍 k近邻算法是一种基本的分类和回归方法,这里只实现分类的k近邻算法. k近邻算法的输入为实例的特征向量,对应特征空间的点:输出为实例的类别,可以取多类. k近邻算法不具有显式的学习过程,实际上k近邻算法是利用训练数据集对特征向量空间进行划分.将划分的空间模型作为其分类模型. k近邻算法的三要素 k值的选择:即分类决策时选择k个最近邻实例: 距离度量:即预测实例点和训练实例点间的距离,一般使用L2距离即欧氏距离: 分类决策规则. 下面对三要素进行一下说明: 1.欧氏距离即欧几里得距

  • 给你选择Python语言实现机器学习算法的三大理由

    基于以下三个原因,我们选择Python作为实现机器学习算法的编程语言:(1) Python的语法清晰:(2) 易于操作纯文本文件:(3) 使用广泛,存在大量的开发文档. 可执行伪代码 Python具有清晰的语法结构,大家也把它称作可执行伪代码(executable pseudo-code).默认安装的Python开发环境已经附带了很多高级数据类型,如列表.元组.字典.集合.队列等,无需进一步编程就可以使用这些数据类型的操作.使用这些数据类型使得实现抽象的数学概念非常简单.此外,读者还可以使用自己

随机推荐