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

如何高效匹配Pandas列值与列表元素并获取最近值?

问题:为Pandas DataFrame高效添加最近值列

给定列表 [5, 30, 60, 180, 240],以及如下结构的DataFrame(id1+id2组合唯一,同一id1的记录共享feat1值):

id1 id2 feat1
1     1   40
1     2   40
1     3   40
1     4   40
2     6   87
2     7   87
2     8   87

需要新增closest_number列,值为对应feat1与列表中最接近的元素,期望输出如下:

id1 id2 feat1 closest_number
1     1   40      30
1     2   40      30
1     3   40      30
1     4   40      30
2     6   87      60
2     7   87      60
2     8   87      60

已有计算最近值的函数:

def get_closest(array, values):
    # make sure array is a numpy array
    array = np.array(array)

    # get insert positions
    idxs = np.searchsorted(array, values, side="left")
    
    # find indexes where previous index is closer
    prev_idx_is_less = ((idxs == len(array))|(np.fabs(values - array[np.maximum(idxs-1, 0)]) < np.fabs(values - array[np.minimum(idxs, len(array)-1)])))
    idxs[prev_idx_is_less] -= 1
    
    return array[idxs]

调用该函数会返回array([30, 60]),但无法直接对应到原DataFrame的行。当前通过生成距离列选最小值实现,需要更优雅高效的方案。


解决方案

核心思路

利用同一id1共享feat1的特性,只对每个id1的唯一feat1值计算一次最近值,再将结果映射/广播到该组所有行,避免重复计算,提升效率。

方法1:groupby + map

import pandas as pd
import numpy as np

# 定义输入数据
num_list = [5, 30, 60, 180, 240]
df = pd.DataFrame({
    'id1': [1,1,1,1,2,2,2],
    'id2': [1,2,3,4,6,7,8],
    'feat1': [40,40,40,40,87,87,87]
})

# 复用已有函数
def get_closest(array, values):
    array = np.array(array)
    idxs = np.searchsorted(array, values, side="left")
    prev_idx_is_less = ((idxs == len(array)) | 
                        (np.fabs(values - array[np.maximum(idxs-1, 0)]) < 
                         np.fabs(values - array[np.minimum(idxs, len(array)-1)])))
    idxs[prev_idx_is_less] -= 1
    return array[idxs]

# 提取每个id1的唯一feat1,计算对应最近值
closest_mapping = df.groupby('id1')['feat1'].first().apply(lambda x: get_closest(num_list, x))

# 将结果映射回原DataFrame
df['closest_number'] = df['id1'].map(closest_mapping)

方法2:groupby + transform(更简洁)

transform会自动将组内计算结果广播到该组所有行,无需额外映射步骤:

df['closest_number'] = df.groupby('id1')['feat1'].transform(lambda x: get_closest(num_list, x.iloc[0]))

验证输出

执行上述代码后,输出结果与期望一致:

id1  id2  feat1  closest_number
0    1    1     40              30
1    1    2     40              30
2    1    3     40              30
3    1    4     40              30
4    2    6     87              60
5    2    7     87              60
6    2    8     87              60

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 09:50:42