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

np.argsort与pd.nsmallest取最小k值结果不一致,如何修正np.argsort用法

问题:使用np.argsort实现与pd.nsmallest一致的最小误差列选取功能

示例数据与基础代码

import pandas as pd
import numpy as np

np.random.seed(2021)
dates = pd.date_range('20130226', periods=90)
df = pd.DataFrame(np.random.uniform(0, 10, size=(90, 4)), index=dates, columns=['A_values', 'B_values', 'C_values', 'target'])

# 计算mape的函数
def mape(y_true, y_pred):
    y_pred = np.array(y_pred)
    return np.mean(np.abs(y_true - y_pred) / np.clip(np.abs(y_true), 1, np.inf),
                   axis=0)*100

preds = df.columns[df.columns.str.endswith('_values')]
k = 2
print(df)

输出结果:

A_values  B_values  C_values    target
2013-02-26  6.059783  7.333694  1.389472  3.126731
2013-02-27  9.972433  1.281624  1.789931  7.529254
2013-02-28  6.621605  7.843101  0.968944  0.585713
2013-03-01  9.623960  6.165574  0.866300  5.612724
2013-03-02  6.165247  9.638430  5.743043  3.711608
             ...       ...       ...       ...
2013-05-22  0.589729  6.479978  3.531450  6.872059
2013-05-23  6.279065  3.837670  8.853146  8.209883
2013-05-24  5.533017  5.241127  1.388056  5.355926
2013-05-25  1.596038  4.665995  2.406251  1.971875
2013-05-26  3.269001  1.787529  6.659690  7.545569

[90 rows x 4 columns]

需求说明

需要计算MAPE值,通过两种方法对数据按年月分组,选取每组误差最小的2个值:

方法1:错误的np.argsort实现

def grpProc(grp):
    err = mape(grp[preds], grp[['target']])
    print(err)
    sort_args = np.argsort(err, axis=1) < k
    cols = preds[sort_args]
    print(cols)
    print('-'*50)

df.groupby(pd.Grouper(freq='M')).apply(grpProc)

输出结果:

A_values     54.685258
B_values    212.458242
C_values    161.332752
dtype: float64
Index(['A_values', 'C_values'], dtype='object')
--------------------------------------------------
A_values     77.504315
B_values    128.986127
C_values    118.977186
dtype: float64
Index(['A_values', 'C_values'], dtype='object')
--------------------------------------------------
A_values    132.535352
B_values    150.886936
C_values     94.279492
dtype: float64
Index(['B_values', 'C_values'], dtype='object')
--------------------------------------------------
A_values    150.554314
B_values    114.113724
C_values     92.487276
dtype: float64
Index(['B_values', 'C_values'], dtype='object')
--------------------------------------------------

方法2:正确的pd.nsmallest实现

def grpProc(grp):
    err = mape(grp[preds], grp[['target']])
    print(err)
    cols = err.nsmallest(k).index
    print(cols)
    print('-'*50)

df.groupby(pd.Grouper(freq='M')).apply(grpProc)

输出结果:

A_values     54.685258
B_values    212.458242
C_values    161.332752
dtype: float64
Index(['A_values', 'C_values'], dtype='object')
--------------------------------------------------
A_values     77.504315
B_values    128.986127
C_values    118.977186
dtype: float64
Index(['A_values', 'C_values'], dtype='object')
--------------------------------------------------
A_values    132.535352
B_values    150.886936
C_values     94.279492
dtype: float64
Index(['C_values', 'A_values'], dtype='object')
--------------------------------------------------
A_values    150.554314
B_values    114.113724
C_values     92.487276
dtype: float64
Index(['C_values', 'B_values'], dtype='object')
--------------------------------------------------

可以看到方法1在第三组返回了错误结果,正确结果应为['C_values', 'A_values']。

正确的np.argsort实现

问题原因

原来的错误写法使用np.argsort(err, axis=1) < k生成布尔索引筛选列,会保持preds原有的列顺序,不会按误差大小排序,还会出现匹配错误。

正确代码

def grpProc(grp):
    err = mape(grp[preds], grp[['target']])
    print(err)
    # 获取误差升序排序后的下标,取前k个
    sorted_idx = np.argsort(err.values)[:k]
    cols = preds[sorted_idx]
    print(cols)
    print('-'*50)

df.groupby(pd.Grouper(freq='M')).apply(grpProc)

逻辑说明

  • np.argsort对一维的误差数组默认按升序排序,返回的是原数组元素从小到大排列对应的索引下标
  • 直接取前k个下标,再用preds索引这些下标,得到的列顺序和pd.nsmallest返回的顺序完全一致,都是按误差从小到大排列
  • 完全复现pd.nsmallest的返回结果,不会出现匹配错误或顺序错误的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 01:45:03