Box-Cox変換

Prep

Box-Cox変換

Box-Cox変換は、すべての観測値が正のときに歪度を抑え、分散を安定させるためのパワー変換です。ゼロや負の値が含まれる場合はデータを定数でシフトするか、Yeo-Johnson 変換への切り替えを検討します。

定義 #

正の観測値 (x > 0) とパラメーター (\lambda) に対して Box-Cox 変換 (T_\lambda(x)) は

$$ T_\lambda(x) = \begin{cases} \dfrac{x^\lambda - 1}{\lambda}, & \lambda \ne 0,\\ \log x, & \lambda = 0. \end{cases} $$

  • (\lambda = 1) ならば値はそのまま、(\lambda = 0) では自然対数になります。
  • 逆変換は scipy.special.inv_boxcox として提供されています。
  • (\lambda) の最尤推定は scipy.stats.boxcox_normmax で求められます。

式に (x^\lambda) と (\log x) が含まれるため、入力は必ず正の値に制限されます。必要に応じて小さな正の定数を加えてください。

実装例 #

import numpy as np
import matplotlib.pyplot as plt

rng = np.random.default_rng(42)
x = rng.lognormal(mean=1.5, sigma=0.6, size=1_000)
plt.figure(figsize=(6, 4))
plt.hist(x, bins=30, color="steelblue")
plt.title("変換前(正の値だが歪みが大きい)")
plt.show()

実装例の図

from scipy.stats import boxcox, boxcox_normmax

lmbda = boxcox_normmax(x)  # lambda の最尤推定
print(f"推定された lambda: {lmbda:.3f}")

x_trans = boxcox(x, lmbda=lmbda)
plt.figure(figsize=(6, 4))
plt.hist(x_trans, bins=30, color="seagreen")
plt.title("Box-Cox 変換後")
plt.show()

実装例の図

変換後の分布は左右対称に近づき、線形モデルや距離ベースの手法が扱いやすい形になります。

実務でのヒント #

  • (\lambda) は学習データで推定し、検証・テストでも同じ値を再利用して情報漏洩を防ぎます。
  • 予測結果を元のスケールに戻したい場合は inv_boxcox を利用します。
  • モデルが平均 0・分散 1 を要求するなら、Box-Cox の後に StandardScaler などを組み合わせると安定します。
  • 入力に 0 や負の値が含まれるときは Yeo-Johnson 変換か、定数シフトを検討してください。