You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对DataFrame每行值排序返回列名及实现DataFrame间最近点匹配

嘿,我来帮你解决这两个Pandas的问题,都是实际数据分析里很实用的需求:

问题1:对DataFrame每行的值排序,返回对应的列名称

这个需求其实挺常见的,比如你想知道每行里数值从大到小(或从小到大)对应的列是哪些。咱们可以用Pandas的apply方法,结合sort_values和索引来实现,举个具体的例子:

先创建一个测试用的DataFrame:

import pandas as pd
df = pd.DataFrame({
    'A': [3, 1, 2],
    'B': [1, 3, 2],
    'C': [2, 2, 1]
})

然后对每行的值排序,返回排序后的列名列表:

# 按升序排序,返回列名
sorted_cols_asc = df.apply(lambda row: row.sort_values(ascending=True).index.tolist(), axis=1)
# 如果要降序,把ascending改成False就行
sorted_cols_desc = df.apply(lambda row: row.sort_values(ascending=False).index.tolist(), axis=1)

解释一下:axis=1告诉Pandas我们要按行处理,row.sort_values()会把当前行的数值排序,然后.index就能拿到排序后数值对应的列名,转成列表就是每行的结果。运行后你会得到一个Series,每个元素是对应行的列名排序列表。


问题2:不同行数DataFrame的经纬度最近点匹配

这个需求是地理数据分析里的经典场景,因为是经纬度点,咱们优先用哈维正弦公式计算球面距离(比欧氏距离更准确,适合全球范围的点)。你的数据量不算特别大(1098×1331≈146万次计算),暴力匹配完全能搞定,如果数据量再大的话,可以用KD-Tree优化,我两种方法都给你讲讲:

方法1:暴力匹配(适合中小数据量)

首先先实现哈维距离的计算函数:

import numpy as np

def haversine(lat1, lon1, lat2, lon2):
    # 把经纬度转成弧度(三角函数计算需要弧度)
    lat1, lon1, lat2, lon2 = map(np.radians, [lat1, lon1, lat2, lon2])
    # 哈维公式核心计算
    dlat = lat2 - lat1
    dlon = lon2 - lon1
    a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2)**2
    c = 2 * np.arcsin(np.sqrt(a))
    # 地球平均半径,单位是公里,如果你要米的话改成6371000
    r = 6371
    return c * r

然后遍历df1的每个点,计算它到df2所有点的距离,找到最近的那个:

# 先把df2的经纬度提取成数组,方便批量计算
df2_coords = df2[['lat-1', 'long-1']].values

def find_nearest_point(row):
    # 取出当前df1行的经纬度
    lat, lon = row['lat-2'], row['long-2']
    # 计算到df2所有点的距离
    distances = haversine(lat, lon, df2_coords[:, 0], df2_coords[:, 1])
    # 找到距离最小的点的索引
    nearest_idx = np.argmin(distances)
    # 返回df2中对应的那一行数据
    return df2.iloc[nearest_idx]

# 对df1每行应用这个函数,得到匹配结果
matched_data = df1.apply(find_nearest_point, axis=1)
# 把匹配结果和原df1合并,加个后缀区分
final_result = pd.concat([df1, matched_data.add_suffix('_nearest')], axis=1)

看你的示例数据,比如df1的R1点(10.612811, 46.265142)和df2的G2点完全重合,运行后会匹配到G2,距离为0,完全符合预期。

方法2:KD-Tree优化(适合大数据量)

如果你的数据量再大几倍,暴力法就会很慢,这时候可以用scipy的cKDTree来加速最近邻查询:

from scipy.spatial import cKDTree

# 把经纬度转成弧度,构建KD-Tree(注意:KD-Tree默认用欧氏距离,小范围经纬度误差很小,大范围建议用球面KD-Tree,不过一般场景这个足够)
df2_rad = np.radians(df2[['lat-1', 'long-1']].values)
tree = cKDTree(df2_rad)

# 处理df1的经纬度
df1_rad = np.radians(df1[['lat-2', 'long-2']].values)
# 查询每个点的最近邻,k=1表示只取最近的1个
distances_rad, nearest_indices = tree.query(df1_rad, k=1)

# 把匹配结果合并到df1里
final_result = df1.copy()
final_result['nearest_id'] = df2.index[nearest_indices]
final_result['nearest_lat'] = df2['lat-1'].iloc[nearest_indices].values
final_result['nearest_long'] = df2['long-1'].iloc[nearest_indices].values
# 用哈维公式计算真实的球面距离(因为KD-Tree返回的是弧度欧氏距离,不是实际公里数)
final_result['distance_km'] = haversine(
    final_result['lat-2'], final_result['long-2'],
    final_result['nearest_lat'], final_result['nearest_long']
)

这个方法的查询效率会比暴力法高很多,尤其是当df2的行数超过几万的时候,优势特别明显。


内容的提问来源于stack exchange,提问作者Amanda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:36:34