统计学习方法第三章:k近邻法(k-NN),kd树及python实现

程序员通勤双肩包,下单送全年 CSDN 会员 防泼水面料电脑包,保护笔记本电脑,背负轻便,下单再赠 Coding Plan,看技术干货、查文档、下载源码,一站式搞定学习需求 阅读详情

统计学习方法第二章:感知机(perceptron)算法及python实现
统计学习方法第三章:k近邻法(k-NN),kd树及python实现
统计学习方法第四章:朴素贝叶斯法(naive Bayes),贝叶斯估计及python实现
统计学习方法第五章:决策树(decision tree),CART算法,剪枝及python实现
统计学习方法第五章:决策树(decision tree),ID3算法,C4.5算法及python实现

完整代码:
https://github.com/xjwhhh/LearningML/tree/master/StatisticalLearningMethod
欢迎follow和star

k近邻法(k-nearest neighbor,k-NN)是一种基本分类与回归方法。

k近邻法假设给定一个训练数据集,其中的实例类别已定。分类时,对新的实例,根据其k个最近邻的训练实例的类别,通过多数表决等方式进行预测。因此,k邻近法不具有显式的学习过程。

k近邻法实际上利用训练数据集对特征空间进行划分,并作为其分类的“模型”。

k值的选择,距离度量及分类决策规则是k近邻法的三个基本要素。

下图是k近邻法:
k近邻法

实现k近邻法时,主要考虑的问题是如何对训练数据进行快速k近邻搜索。这点在特征空间的维数大以及训练数据容量大时尤其必要

k近邻法最简单的实现方式是线性扫描。这时要计算输入实例与每一个训练实例的距离,当训练集很大时,计算非常耗时,这种方法是不可行的

为了提高k近邻搜索的效率,可以考虑使用特殊的结构存储训练数据,以减少计算距离的次数。其中一种方法就是kd树方法

下图是kd树的构造算法:
kd树构造算法

下图是kd树的搜索算法:
kd树搜索算法

更具体的解释和证明可以看《统计学习方法》或者其他解释kd树的博文,我在这里不再赘述

下面是python代码实现,使用MINST数据集,构造kd树进行搜索,实现的是最近邻算法,即只搜寻最近的一个实例来决定类别

但有一个问题是运算很慢,我也不得其解,但算法核心部分实现应当是无误的

import pandas as pd
import numpy as np
import cv2
import logging
import time

from math import sqrt
from collections import namedtuple

from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score


def log(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        logging.debug('start %s()' % func.__name__)
        ret = func(*args, **kwargs)

        end_time = time.time()
        logging.debug('end %s(), cost %s seconds' % (func.__name__, end_time - start_time))

        return ret

    return wrapper


def get_hog_features(trainset):
    # 利用opencv获取图像hog特征

    features = []

    hog = cv2.HOGDescriptor('../hog.xml')

    for img in trainset:
        img = np.reshape(img, (28, 28))
        cv_img = img.astype(np.uint8)

        hog_feature = hog.compute(cv_img)
        # hog_feature = np.transpose(hog_feature)
        features.append(hog_feature)

    features = np.array(features)
    features = np.reshape(features, (-1, 324))

    return features


def predict(test_set, kd_tree):
    predict = []

    for i in range(len(test_set)):
        predict.append(find_nearest(kd_tree, test_set[i]).label)

    return np.array(predict)

class KdNode(object):
    def __init__(self, dom_elt, split, left, right, label):
        self.dom_elt = dom_elt  # k维向量节点(k维空间中的一个样本点)
        self.split = split  # 整数(进行分割维度的序号)
        self.left = left  # 该结点分割超平面左子空间构成的kd-tree
        self.right = right  # 该结点分割超平面右子空间构成的kd-tree
        self.label = label


class KdTree(object):

    @log
    def __init__(self, data, labels):
        k = len(data[0])  # 数据维度

        def create_node(split, data_set, labels):  # 按第split维划分数据集,创建KdNode

            # print(len(data_set))
            if (len(data_set) == 0):
                return None

            sort_index = data_set[:, split].argsort()
            data_set = data_set[sort_index]
            labels = labels[sort_index]
            # print(data_set)

            split_pos = len(data_set) // 2
            # print(split_pos)
            median = data_set[split_pos]  # 中位数分割点
            label = labels[split_pos]
            split_next = (split + 1) % k  # cycle coordinates

            # 递归的创建kd树
            return KdNode(median, split,
                          create_node(split_next, data_set[:split_pos], labels[:split_pos]),  # 创建左子树
                          create_node(split_next, data_set[split_pos + 1:], labels[split_pos + 1:]),  # 创建右子树
                          label)

        self.root = create_node(0, data, labels)  # 从第0维分量开始构建kd树,返回根节点


# 定义一个namedtuple,分别存放最近坐标点、最近距离和访问过的节点数
result = namedtuple("Result_tuple", "nearest_point  nearest_dist  nodes_visited label")


@log
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, 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
        if (nearer_node is None):
            label = 0
        else:
            label = nearer_node.label

        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, temp1.label)  # 不相交则可以直接返回,不用继续判断

        # ----------------------------------------------------------------------
        # 计算目标点与分割点的欧氏距离
        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  # 更新超球体半径
            label = kd_node

        # 检查另一个子结点对应的区域是否有更近的点
        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  # 更新最近距离
            label = temp2.label

        return result(nearest, dist, nodes_visited, label)

    return travel(tree.root, point, float("inf"))  # 从根节点开始递归


k = 10

if __name__ == '__main__':
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)

    raw_data = pd.read_csv('../data/train.csv', header=0)
    data = raw_data.values

    images = data[0:, 1:]
    labels = data[:, 0]

    features = get_hog_features(images)
    # 选取 2/3 数据作为训练集, 1/3 数据作为测试集
    train_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size=0.33,random_state=1)

    kd_tree = KdTree(train_features, train_labels)

    test_predict = predict(test_features, kd_tree)

    score = accuracy_score(test_labels, test_predict)
    print("The accuracy score is ", score)

水平有限,如有错误,希望指出

python实现kd以及最近邻查找算法 python实现kd以及最近邻查找算法一、kd简介二、kd生成1.确定切分域2.确定数据域3.理解递归4.python实现递归代码三、kd上的最近邻查找算法 一、kd简介 kd是一种形结构,的每个节点存放一个k维数据,某一节点的子节点可以看作是由过该节点一个平面切割后产生的(想象一下切蛋糕的过程),如此反复产生切割平面,就能为每个数据在空间中建立索引,如下图所示: 由于采用这种特殊的分割方式,使得在利用kd最近邻查找时,可以避开一些距离很远的点,查找速度得到了较大的提升,对于空间中 阅读详情

相关推荐

K近邻法kd及其Python实现

作为机器学习中一种基本的分类方法,K近邻(KNN)法是一种相对简单的方法。其中一个理由是K近邻法不需要对训练集进行学习。然而,不需要对训练集进行学习,反过来也会造成对测试集进行判定时,计算与空间复杂度的增加。 K近邻法最简单的实现方法是对需要分类的目标点,计算出训练集中每一个点到其的距离(比较常用的有欧氏距离),然后选取K个距离目标最近的点,根据这些点的分类以多数表决的形式来决定目标点的分类。理

反魂蝶,八分咲 9363

python K近邻算法kd实现

主要介绍了python K近邻算法kd实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

统计学习方法:李航》笔记 从原理到实现(基于python-- 第3章 k邻近邻法

统计学习方法:李航》笔记 从原理到实现(基于python-- 第3章 k邻近邻法

weixin_42046845的博客 1433

统计学习方法》 k近邻Python kd实现

统计学习方法》中,kdPython实现

kd python实现_统计学习方法第三章:k近邻法(k-NN),kdpython实现

欢迎关注公众号:常失眠少年,大学生的修炼手册!k近邻法(k-nearest neighbor,k-NN)是一种基本分类与回归方法。k近邻法假设给定一个训练数据集,其中的实例类别已定。分类时,对新的实例,根据其k个最近邻的训练实例的类别,通过多数表决等方式进行预测。因此,k邻近法不具有显式的学习过程。k近邻法实际上利用训练数据集对特征空间进行划分,并作为其分类的“模型”。k值的选择,距离度量及分类决...

weixin_39643336的博客 401

Python KD搜索】——构建高效的数据结构实现近邻搜索

通过这种方式,KD将数据点分布在一颗平衡的二叉中,使得最近邻查询的时间复杂度可以达到O(logn),相较于线性扫描的复杂度O(n)更加高效。为了评估KD的性能,我们需要考虑三个因素:数据集的维度、查询点的数量和数据集的大小。通常情况下,随着数据集的维度增加,KD的性能会迅速下降,因为高维空间中数据点的数量呈指数级增长。通过本文的介绍,您应该已经了解了如何使用Python KD搜索来构建高效的数据结构,并如何度量算法的性能。通过测试不同维度的数据集,我们可以对KD的性能有一个初步的认识。

. 881

机器学习:k近邻算法Python

代码】机器学习:k近邻算法Python

2302_78896863的博客 1336

(3)点云数据处理学习——KD近邻搜索

dd

chencaw的专栏 1780

kd的根节点_统计学习方法第三章:k近邻法(k-NN),kdpython实现

完整代码:xjwhhh/LearningML​github.com欢迎follow和star欢迎关注公众号:常失眠少年,谢谢。k近邻法(k-nearest neighbor,k-NN)是一种基本分类与回归方法。k近邻法假设给定一个训练数据集,其中的实例类别已定。分类时,对新的实例,根据其k个最近邻的训练实例的类别,通过多数表决等方式进行预测。因此,k邻近法不具有显式的学习过程。k近邻法实际上利用训...

weixin_42232139的博客 145

k近邻法的原理与实现

一、基本概念k近邻法(k-nearest neighbor, k-NN)是一种基本分类与回归方法,由Cover和Hart于1968年提出。分类时,对于新的实例,根据与它最接近的k个训练实例的类别,通过多数表决等方式,进行预测。对于给定的训练集,当k值,距离度量和分类决策规则(统称三要素)确定后,基于k近邻法的模型就已经确定了。所以,它实际上利用训练集对特征向量空间进行划分,并没有显示的学习过程。k...

beckham999221的专栏 5842

KD改进的K近邻算法python实现

包含 基本的KNN算法python实现KD的构建与使用 以及结合KD的KNN算法,在提取K个最近邻值时采用了大顶堆。 内含每个函数的详细注释,并有一组测试data,经测试程序完善可用

李航统计学习方法 Chapter3 k近邻法

如果想了解更多的知识,可以去我的机器学习之路 The Road To Machine Learning通道 第3章 k近邻法 1.kkk近邻法是基本且简单的分类与回归方法。kkk近邻法的基本做法是:对给定的训练实例点和输入实例点,首先确定输入实例点的kkk个最近邻训练实例点,然后利用这kkk个训练实例点的类的多数来预测输入实例点的类。 2.kkk近邻模型对应于基于训练数据集对特征空间的一个划分。kkk近邻法中,当训练集、距离度量、kkk值及分类决策规则确定后,其结果唯一确定。 3.kkk近邻法三要素:距离度

风信子的猫Redamancy的快乐星球 1万+

【机器学习】k近邻法

本文系统介绍了k近邻算法(k-NN)及其实现方法。k-NN是一种基于实例的分类与回归方法,通过计算输入实例与训练数据的距离,选择k个最近邻点进行分类决策。文章详细阐述了k-NN的三要素:距离度量(包括欧氏、曼哈顿等)、k值选择(影响模型复杂度)和分类决策规则(如多数表决)。重点介绍了kd这一高效实现方式,包括其构造方法(递归划分特征空间)和搜索算法(回溯查找最近邻)。通过Python代码实现了距离计算、kd构建和最近邻搜索功能,并以二维空间示例验证了算法有效性。最后指出平衡kd虽能提高搜索效率。

2401_84149564的博客 1419

李航《统计学习方法第三章——用Python实现KNN算法(MNIST数据集

相关文章: 李航《统计学习方法》第二章——用Python实现感知器算法(MNIST数据集) 李航《统计学习方法》第四章——用Python实现朴素贝叶斯分类器(MNIST数据集) 看了第三章 k近邻法 (k-nearest neighbor, k-NN) , 发现KNN算法真的好适合在MNIST数据集上分类。因为KNN实际上就是一个少数服从多数的投票模型,所以可以用在多分类的

wds2006sdo的专栏 2万+

k近邻算法实现:kd

1. 问题简介 以下引用自维基百科 在模式识别领域中,最近邻居法(KNN算法,又译K-近邻算法)是一种用于分类和回归的非参数统计方法。在这两种情况下,输入包含特征空间中的k个最接近的训练样本。 在k-NN分类中,输出是一个分类族群。一个对象的分类是由其邻居的“多数表决”确定的,k个最近邻居(k为正整数,通常较小)中最常见的分类决定了赋予该对象的类别。若k = 1,则该对象的类别直

Chopin_xqb的博客 722

3. k 近邻法 k-NN

机器学习算法 k-NN,以及 kd 实现

LION 笔记本 613

【李航】统计学习方法--3. k近邻法(详细推导)

k近邻算法 k近邻法(k-nearest neighbor,k-NN):给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最近邻的k个实例,这k个实例的多数属于某个类,就把该输入实例分为这个类。KNN使用的模型实际上对应于特征空间的划分,没有显式的训练过程。 k近邻模型 模型 该模型有三个基本要素: 距离度量,k值的选择,分类决策规则 .当这三个要素确定后,便能对于任何一个新的输入实例,给出唯一确定的分类.这里用图片说明更清楚,对于训练集中的每一个样本,距离该点比其他点更近的所有点

顾道长生的科研笔记 902

k近邻(k-nearest neighbor,k-NN)及其实现 - kd(k-dimensional tree)

统计学习方法》李航 - 第3章 1. 概述 1.1 定义 k近邻法(k-nearest neighbor,k-NN)分类算法是数据挖掘分类技术中最简单的方法之一。所谓K最近邻,就是k个最近的邻居的意思,说的是每个样本都可以用它最接近的k个邻居来代表。 简单来说就是:在样本空间(训练集)中,与待测样本最相邻(通过距离度量)的k个样本中,大多数属于某一个类别,则该待测样本也属于这个类别,并具...

CCC的专栏 1198
上一篇: 统计学习方法第二章:感知机(perceptron)算法及python实现
下一篇: 统计学习方法第四章:朴素贝叶斯法(naive Bayes),贝叶斯估计及python实现
不晓得X
博客等级 码龄10年 114粉丝 50原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值