Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

IdxMax and IdxMin return the position of NaN instead of the extreme value

オープン 初心者向け
#2,352 コメント 4 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 3 日以内に返信

@bozarnr がすでに取り組んでいます。

2026年9月23日 から。

  • #2353 @LudwigJMarx による — オープン
  • #2356 @bozarnr による — オープン

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
78/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
numpy, pandas, python

調査の方向性

まず qlib/data/ops で IdxMax と IdxMin を見つけ、実際のオペレーターに対して提供された再現スクリプトを実行します。次に、qlib/contrib/data/loader.py の関連する IMAX、IMIN、IMXD 式を確認し、ウィンドウに NaN 値が含まれる場合にインデックス付きの結果が Max および Min と一致することを検証します。

索引モデルが issue の本文から書いたものです。

説明

🐛 Bug Description

IdxMax and IdxMin return the position of the extreme value inside the
rolling window. Both use ndarray.argmax / ndarray.argmin, which do not skip
NaN: as soon as the window holds a NaN, they return its position instead.

Max and Min go through pandas.rolling.max/min and do skip NaN, so the two
contradict each other on the same series. Mad and Rank in the same file
filter NaN explicitly (x[~np.isnan(x)]); IdxMax and IdxMin do not.

This reaches Alpha158. qlib/contrib/data/loader.py builds three field
families on these two operators:

field expression meaning per the comment in the loader
IMAX{d} IdxMax($high, d)/d days since the last high (Aroon)
IMIN{d} IdxMin($low, d)/d days since the last low (Aroon)
IMXD{d} (IdxMax($high,d)-IdxMin($low,d))/d distance between the two

$high and $low are NaN while an instrument is suspended.

To Reproduce

  1. Run the script below on a clean checkout. It only replaces the data access
    of a leaf feature; the operators under test run their real code.
import numpy as np
import pandas as pd
from qlib.data.base import Feature
from qlib.data.ops import IdxMax, Max


class SeriesFeature(Feature):
    def __init__(self, name, values):
        super().__init__(name)
        self._values = values

    def _load_internal(self, instrument, start_index, end_index, freq):
        return pd.Series(self._values, dtype="float64")


values = [1.0, 5.0, np.nan, 2.0, 3.0]
window = 3
idx = IdxMax(SeriesFeature("a", values), window).load("x", 0, len(values) - 1, "day")
mx = Max(SeriesFeature("b", values), window).load("x", 0, len(values) - 1, "day")

for i in range(len(values)):
    w = values[max(0, i - window + 1) : i + 1]
    print(f"{w}  Max={mx.iloc[i]}  IdxMax={idx.iloc[i]}  points at {w[int(idx.iloc[i]) - 1]}")
  1. Output on be725493:
[1.0]  Max=1.0  IdxMax=1.0  points at 1.0
[1.0, 5.0]  Max=5.0  IdxMax=2.0  points at 5.0
[1.0, 5.0, nan]  Max=5.0  IdxMax=3.0  points at nan
[5.0, nan, 2.0]  Max=5.0  IdxMax=2.0  points at nan
[nan, 2.0, 3.0]  Max=3.0  IdxMax=1.0  points at nan

Every window holding a NaN is wrong.

Expected Behavior

IdxMax points at the value Max reports for the same window, and IdxMin at
the value Min reports.

Environment

  • Qlib version: 0.9.8.dev34 (editable install)
  • Python version: 3.12.13
  • OS: MacOS 26.6.2, arm64
  • Commit number: be725493eb1a6bbb42bf11b37aa7669f59610ff1
  • numpy 2.5.3, pandas 2.3.3

Additional Notes

Scale on real data. csi300, 30 instruments, 2019, qlib_data_simple:

measurement value
rows 7320
NaN in $high 76 (1.04 %)
instruments holding at least one NaN 30 of 30
IMAX5 differing between argmax and nanargmax 224 of 7314 (3.06 %)

One NaN spoils the window for N days, so the effect is wider than the share of
NaN itself.

主要言語
Python
スター
49.5k
フォーク
7.8k
PR マージ指標
30日以内にマージされた PR はありません

環境構築

  • Dockerfile または Docker Compose ファイルあり
  • プルリクエストのテンプレートあり
  • コントリビューションガイドなし

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

microsoft/qlib のほかの issue

microsoft/qlib の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。