python中怎么模拟k临近算法
发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,今天就跟大家聊聊有关python中怎么模拟k临近算法,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。本章第一个程序是求向量的范数import m
千家信息网最后更新 2026年11月03日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安全错误
数据库的锁怎样保障安全
西安纸贵互联网科技有限公司
科技赋能下的互联网金融
鸠鸠互联网科技
互联网 科技
礼当家互联网科技
紫鲸互联网科技
融势互联网科技
互联网科技美容
丰台科技园 互联网公司
顶级互联网科技成果有哪些
苏州铭阳互联网科技有限公司
互联网媒体平台算高科技产业
卓翼科技产业互联网合作
美国互联网科技实力
互联网科技数字货币
上海乐五互联网科技有限公司
宁波跨境商互联网科技有限公司
盐城市攀科互联网科技有限公司
互联网科技创新创业项目
北京品多多互联网科技有限公司
互联网科技论文
睿民互联网科技
华中科技有哪些互联网大佬
互联网与医疗科技
中国互联网公司排名锤子科技
恒生互联网科技业指数调整周期
广东工业互联网大赛深圳学泰科技
互联网风格科技公司名称
山东大美朱楼互联网科技有限公司
福州德业互联网科技