python中怎么模拟k临近算法
发表于:2025-01-31 作者:千家信息网编辑
千家信息网最后更新 2025年01月31日,今天就跟大家聊聊有关python中怎么模拟k临近算法,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。本章第一个程序是求向量的范数import m
千家信息网最后更新 2025年01月31日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安全错误
数据库的锁怎样保障安全
网络安全行业十四五规划
方中天网络技术
郴州市计算机软件开发学校
lgwing手机连接不上服务器
软件开发人员的年纪
期货期权软件开发
2005数据库配置
两会网络安全 组织部署
网络安全技术实验室
奥特曼传奇英雄服务器怎么连接上
时间存入数据库
mfc添加数据库视频
北京软件开发跨境电商app
农业银行数据库
网络安全投诉信箱
软件开发一个人做什么
怎么远程服务器
云服务器ecs安全组使用方法
组织部网络安全自查
数据库审计产品交流
nrc数据库
网络安全e讲堂视频
统信系统软件开发用什么
不动产登记数据库的问题
团购网站数据库设计
数据库设计为什么要指标库
北京软件开发者需要什么
濮阳职业技术学院网络安全
九品小县令软件开发者
天河网络安全哪家强