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 変換か、定数シフトを検討してください。