python中怎么模拟k临近算法
发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,今天就跟大家聊聊有关python中怎么模拟k临近算法,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。本章第一个程序是求向量的范数import m
千家信息网最后更新 2025年12月02日python中怎么模拟k临近算法
今天就跟大家聊聊有关python中怎么模拟k临近算法,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
本章第一个程序是求向量的范数
import math# combinations函数用于组合,表示从n中取出m个# 作为对比,permutations函数用于排序,表示从n中依次取出m个# from itertools import combinationsdef L(x, y, p): if len(x) == len(y) and len(x) > 1: # 进行计算的前提 sum = 0 for i in range(len(x)): # i表示下标 sum += math.pow(abs(x[i] - y[i]), p) # pow求幂,abs求绝对值 return math.pow(sum, 1/p) else: return 0x1 = [1, 1]x2 = [5, 1]x3 = [4, 4]for i in range(1, 5): r = {"1-{}".format(c):L(x1, c, p=i) for c in [x2, x3]} print("当前次数:{},当前r:{}".format(i, r)) print("当前最小:") print(min(zip(r.values(), r.keys())))输出结果:
当前次数:1,当前r:{'1-[5, 1]': 4.0, '1-[4, 4]': 6.0}当前最小:(4.0, '1-[5, 1]')当前次数:2,当前r:{'1-[5, 1]': 4.0, '1-[4, 4]': 4.242640687119285}当前最小:(4.0, '1-[5, 1]')当前次数:3,当前r:{'1-[5, 1]': 3.9999999999999996, '1-[4, 4]': 3.7797631496846193}当前最小:(3.7797631496846193, '1-[4, 4]')当前次数:4,当前r:{'1-[5, 1]': 4.0, '1-[4, 4]': 3.5676213450081633}当前最小:(3.5676213450081633, '1-[4, 4]')第二个程序,模拟k临近算法
思想:遍历所有的点,找出最近的k个点,通过多数表决,决定测试点的分类。这种方法在训练集大时非常耗时。
import numpy as npimport pandas as dpimport matplotlib.pyplot as pltfrom sklearn.datasets import load_irisfrom sklearn.model_selection import train_test_split # 用于划分数据from collections import Counter # 计数器class KNN: def __init__(self, X_train, y_train, n_neighbors=3, p=2): # 设置了k与p,分别表示最临近的3个点,和距离用二范数决定 self.n = n_neighbors self.p = p self.X_train = X_train self.y_train = y_train def predict(self, X): knn_list = [] # 先求出三个点的"距离",这里的k=3,p=2。根据需要修改 for i in range(self.n): dist = np.linalg.norm(X - self.X_train[i], ord=self.p) knn_list.append((dist, self.y_train[i])) # 然后,递归遍历剩下的点,通过判断:距离 是否比 已经计算的距离 小,小就替换。最终这个列表剩下的是最临近的三个点 for i in range(self.n, len(X_train)): max_index = knn_list.index(max(knn_list, key=lambda x:x[0])) dist = np.linalg.norm(X - self.X_train[i], ord=self.p) if knn_list[max_index][0] > dist: knn_list[max_index] = (dist, self.y_train[i]) # 我们将knn_list中最后一行取出来,即取出了最临近的三个点的类别 knn = [k[-1] for k in knn_list] # 用计数器,这一步结果应该是{"1":数量,"0":数量 } count_pairs = Counter(knn) # count_pairs.items()存储的是,[类别,数量] # 按照列表的第二维进行排序,从小到大。 # 这里排序考虑到有些数据不止两种类型。 # [-1][0]取出最后一行的第一维,即最可能的类型 max_possible = sorted(count_pairs.items(), key=lambda x:x[1])[-1][0] return max_possible def score(self, X_test, y_test): right_count = 0 for X, y in zip(X_test, y_test): label = self.predict(X) if label == y: right_count += 1 return right_count/len(X_test)iris = load_iris()df = dp.DataFrame(iris.data, columns=iris.feature_names)df['label'] = iris.targetdf.columns = ["sepal length", "sepal width", "petal length", "petal width", "label"]data = np.array(df.iloc[:100, [0, 1, -1]])X, y = data[:, :-1], data[:, -1]# 将数据划分成训练集和测试集,测试集占比0.25X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)clf = KNN(X_train, y_train)print("评分:")print(clf.score(X_test, y_test))test_point = [5.0, 4.0]print('test point score:{}'.format(clf.predict(test_point))) # 输出这个点可能的类别,1或者0plt.scatter(df[:50]['sepal length'], df[:50]['sepal width'], label="0")plt.scatter(df[50:100]['sepal length'], df[50:100]['sepal width'], label="1")plt.xlabel('sepal length')plt.ylabel('sepal width')plt.legend()plt.show()结果: 评分大多数时候1.0,偶尔0.96
用kd树实现k临近算法
在训练集很大时,我们通过构架kd树以加快检索速度。
构造kd树思想:依次选择坐标轴(即,依次选择不同的特征)进行切分,并且切分点通常选择坐标轴的中位数,这样构造的kd树是平衡的。注意:平衡的kd树搜索时的效率未必是最优的。注意,"依次选择不同的特征"这句话,如果说不同的特征每个都用了一次了,但是此时的叶节点仍有多个数据,这时候需要返回第一个特征再次进行划分。所以通常的特征选择公式 ( J mod k ) + 1,其中J为当前节点深度(根节点深度为0),k为样品特征个数。
在这个例子中,程序选择坐标轴(即特征)是从0开始的,这样子并不一定合理。
更合理的选择特征的方式是:选当前所有特征中方差最大的特征。因为这样子方便我们更快的搜索出最近邻。就好比梯度下降中,我们从椭圆的中心向边缘下降。如果我们从椭圆的长轴下降 花费的时间 自然比 从短轴下降 花费的时间 要多!再比如,下山,方差大就好比陡一些,方差小就好比缓一些,我们自然选择陡一些的,这样我们可以更快地下山。
from math import sqrtfrom collections import namedtuplefrom time import clockfrom random import random# 定义一个namedtuple,分别存放最近坐标点、最近距离和访问过的节点数result = namedtuple("Result_tuple", "nearest_point nearest_dist nodes_visited")# 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-treeclass 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)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")) # 从根节点开始递归# data = [[2, 3], [5, 4], [9, 6], [4, 7], [8, 1], [7, 2]]# kd = KdTree(data)# preorder(kd.root) # 前序遍历kd树# 产生一个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)]N = 400000t0 = clock() # python3.8 移除了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) # 输出找打的最近点相关信息看完上述内容,你们对python中怎么模拟k临近算法有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。
数据
节点
特征
目标
选择
结点
更新
最小
函数
次数
子树
算法
向量
维度
排序
不同
三个
内容
参数
坐标
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
镇街网络安全工作总结
舟山手机软件开发哪家强
互联网时代智能科技产品
小迪的网络安全培训视频资源
泰州政务软件开发定制
怎么制作网络安全方面的书签
数据库表头英文
什么是负责统筹协调网络安全工作
上海昕天软件开发中心
服务器机箱改装双电源
火绒服务器联动更新安装包
上海交大网络安全与推免
数据库中查询代码文件在哪
数据库账套查询
小学生网络安全教育主题班会课件
计算机软件开发前端和后端
从乌克兰危机看网络安全的重要性
专门的数据库管理员
我的世界如何建造一个服务器主城
一二级菜单怎么设计数据库
信息网络安全组织管理制度
日志易 机器数据库
徐州个人软件开发诚信合作
德州电商软件开发
数据库为什么不能识别
数据库语言中什么是关系
北京师范大学服务器云主机
wifi网络安全性选择
选择网络技术生产厂家
金山网络技术