使用sklearn对经纬度执行最近邻搜索遇错及结果保留需求
问题解决与代码修正
1. 先搞定TypeError
你报错的核心原因是把数据直接传给了NearestNeighbors的构造函数,但这个类的初始化方法不需要提前传数据,数据是通过fit()方法传入的。另外要注意:用haversine度量时,sklearn要求坐标必须是弧度制(不是原始的经纬度度数),否则计算出的距离会完全错误。
2. 修正后的完整代码
import numpy as np from sklearn.neighbors import NearestNeighbors import pandas as pd # 把经纬度转成弧度(haversine度量的硬性要求) df['lat_rad'] = np.radians(df['lat']) df['long_rad'] = np.radians(df['long']) # 准备弧度坐标数组 coords_rad = df[['lat_rad', 'long_rad']].values # 正确初始化NearestNeighbors,只传算法和度量参数 btree = NearestNeighbors(algorithm='ball_tree', metric='haversine') # 再传入数据拟合模型 btree.fit(coords_rad) # 示例1:给每个点匹配最近邻(排除自身) # kneighbors返回两个数组:距离(弧度)、最近邻的索引 distances, indices = btree.kneighbors(coords_rad, n_neighbors=2) # n_neighbors=2是因为第一个结果是点自身 # 把最近邻的名称、坐标关联到原DataFrame df['nearest_neighbor_name'] = df['name'].iloc[indices[:, 1]].values df['nearest_neighbor_lat'] = df['lat'].iloc[indices[:, 1]].values df['nearest_neighbor_long'] = df['long'].iloc[indices[:, 1]].values # 把弧度距离转成公里(地球半径取6371km) df['neighbor_distance_km'] = distances[:, 1] * 6371 # 示例2:生成完整的优化路线(贪心最近邻顺序) route_indices = [0] # 从第一个点开始 remaining_indices = set(range(len(df))) remaining_indices.remove(0) while remaining_indices: # 取路线最后一个点的坐标 last_point = coords_rad[route_indices[-1]].reshape(1, -1) # 找剩余点中最近的那个 dists, idxs = btree.kneighbors(last_point, n_neighbors=len(remaining_indices)+1) # 过滤掉已经在路线里的点 for idx in idxs[0]: if idx in remaining_indices: route_indices.append(idx) remaining_indices.remove(idx) break # 生成保留原始名称和坐标的路线DataFrame optimised_route_df = df.iloc[route_indices].reset_index(drop=True)[['name', 'lat', 'long']] print(optimised_route_df)
3. 关键说明
- 不要把
NearestNeighbors实例直接赋值给DataFrame列:btree是模型对象,不能存到表格里,要把搜索得到的具体结果(名称、坐标、距离)存入。 - 弧度转换是必做步骤:haversine公式基于弧度计算,直接用度数会导致距离完全失真。
- 贪心路线是基础实现:如果需要更优的路径(比如旅行商问题级别的最优解),需要用专门的TSP算法,但这个方法能满足基础的顺序需求。
内容的提问来源于stack exchange,提问作者Milo
相关产品推荐
相关产品推荐

