如何高效匹配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
相关产品推荐
相关产品推荐

