2023-7-19

ボンフェローニ補正付きコルモゴロフ・スミルノフ検定

機械学習

python

自動取引

予測で使っているデータに問題が無いことを確認するためにボンフェローニ補正したコルモゴロフ・スミルノフ(KS)検定で特徴量の異常を検知する。 ボンフェローニ補正についてはwikipediaが詳しかったので、これを参考に実装した。 KS検定はscipyに実装があるので楽に実装できた。

ボンフェローニ補正自体はそんなに難しい概念ではなくて、複数回検定すると偶然棄却されてしまう可能性が上がるので、 全体で行う検定の回数に応じて、各検定の有意水準を割ることで補正を加えるという話のようだ。

python
Copied!
def ks_test(
    df1: pd.DataFrame, df2: pd.DataFrame, significant_level: float = 0.05, logger: Optional[logging.Logger] = None
) -> bool:
    """kstest with bonferroni correction"""
    if set(df1.columns) != set(df2.columns):
        raise ValueError("Columns are different")

    threshold = significant_level / len(df1.columns)
    reject = False
    for col in df1.columns:
        score = kstest(df1[col], df2[col])
        if score.pvalue < threshold:
            reject = True

        # Log test result
        head = "🆗"
        if score.pvalue < threshold:
            head = "🙅"
        if logger:
            logger.info(f"{head} p={score.pvalue: .3f} < {threshold: .3f} : {col}")
    return reject

ちなみに学習時のデータと予測時のデータを比較してみたところ以下のようなログが出力された(変数名は諸事上でXXXに置き換え処理済み)。 バグってますね。

text
Copied!
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 0.898 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 0.619 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 0.695 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 0.635 >  0.002 : XXX
🆗 p= 0.992 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🆗 p= 1.000 >  0.002 : XXX
🙅 p= 0.000 <  0.002 : XXX
🙅 p= 0.000 <  0.002 : XXX
🙅 p= 0.000 <  0.002 : XXX