K_DM Book
用語集
対象者 標準
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

Yeo-Johnson変換

01.3.5

Yeo-Johnson変換

最終更新 2025-11-03 読了時間 2 分
まとめ
Yeo-Johnson 変換は、Box-Cox 変換を 0 や負の値にも使えるように拡張したパワー変換で、歪んだ分布を左右対称の正規分布に近づけます。正の側は \(y + 1\) に対する Box-Cox 変換、負の側は符号を反転して \(2 - \lambda\) のべきをかける式になっており、0 をまたいでも単調性が保たれます。scipy.stats.yeojohnson_normmax が \(\lambda\) を最尤推定し、scipy.stats.yeojohnson(x, lmbda=...) がその値で変換します。このページでは負の値を含む loggamma 乱数 1,000 点を例に変換前後のヒストグラムを比べ、学習データで決めた \(\lambda\) を検証データにも同じ値で適用する書き方を確認します。

直感 #

気温の変化量や株価のリターンのように、0 をまたいで負の値も取る量は Box-Cox 変換 にそのまま渡せません。\(\log x\) や \(x^{0.5}\) が負の値で定義できないからです。「全体に 100 を足して正にする」という回避策もありますが、足す定数しだいで変換の形が変わってしまいます。Yeo-Johnson 変換は正の側と負の側で別の式を使い、0 でなめらかにつながるように設計されているので、定数を足す判断をせずにそのまま歪みを直せます。右に裾を引いたデータでは \(\lambda < 1\) が選ばれて大きな値が縮み、左に裾を引いたデータでは \(\lambda > 1\) が選ばれて小さな値側が縮みます。

式で見ると正と負でどう分かれているか #

観測値 \(y\) とパラメーター \(\lambda\) に対して、Yeo-Johnson 変換 \(T_\lambda(y)\) は次のように定義されます。

$$ T_\lambda(y)= \begin{cases} \dfrac{(y + 1)^\lambda - 1}{\lambda}, & y \ge 0,\ \lambda \ne 0,\\\\ \log(y + 1), & y \ge 0,\ \lambda = 0,\\\\ -\dfrac{(1 - y)^{2 - \lambda} - 1}{2 - \lambda}, & y < 0,\ \lambda \ne 2,\\\\ -\log(1 - y), & y < 0,\ \lambda = 2. \end{cases} $$

上の 2 行が正の側で、\(y + 1\) に対する Box-Cox 変換と同じ形です。下の 2 行が負の側で、\(1 - y\) という正の量に \(2 - \lambda\) のべきをかけてから符号を戻しています。\(\lambda = 1\) のときはどの行も \(y\) そのものになり、変換しないのと同じです。正の側で \(\lambda\) を小さくすると大きな値が縮む一方、負の側のべきは \(2 - \lambda\) で大きくなるので、負の側は逆に引き伸ばされます。べきを正の側 \(\lambda\)・負の側 \(2 - \lambda\) と分けているおかげで、変換後も値の大小関係(単調性)が崩れません。逆変換は同じ場合分けを \(y\) について解けば得られ、SciPy では scipy.stats.yeojohnson_inverse が実装されています。\(\lambda\) は変換後のデータが正規分布に従うと仮定した対数尤度を最大化して決め、yeojohnson_normmax がその推定値を返します。

I. Yeo and R.A. Johnson, “A New Family of Power Transformations to Improve Normality or Symmetry”, Biometrika 87(4), 2000.

何が起きているか(ステップで見る) #

コードを読む前に、この手法が図の上で何をしているかを追ってみましょう。「再生」を押すか、スライダーを動かすと 1 手順ずつ進みます。

見るポイント:対数は大きな値ほど強く縮める。右に裾を引く分布を対称に近づける定番の変換で、Yeo-Johnson は 0 や負の値でも同じ効果を出せるように対数を拡張したもの。

Python で変換前後を比べる #

次のコードは負の値を含む歪んだ分布を 1,000 点作り、0 の位置に赤い線を引いたヒストグラムを描きます。赤い線の左側に点があることが、Box-Cox では扱えない理由です。

1
2
3
4
5
6
7
8
9
from scipy import stats
import matplotlib.pyplot as plt

# 負の値を含む歪んだ分布を作成
x = stats.loggamma.rvs(1, size=1_000) - 0.5
plt.hist(x, bins=30)
plt.axvline(x=0, color="r")
plt.title("変換前(負の値を含む)")
plt.show()

実装例の図

次のコードは \(\lambda\) を最尤推定してから yeojohnson を適用し、変換後のヒストグラムを描きます。

1
2
3
4
5
6
7
8
9
from scipy.stats import yeojohnson, yeojohnson_normmax

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

x_trans = yeojohnson(x, lmbda=lmbda)
plt.hist(x_trans, bins=30)
plt.title("Yeo-Johnson 変換後")
plt.show()

実装例の図

変換後のヒストグラムは左右対称に近づき、分散も安定します。次のコードは、学習データで得た \(\lambda\) を検証データにそのまま使う書き方です。

1
2
X_train_trans = yeojohnson(X_train, lmbda=lmbda)
X_valid_trans = yeojohnson(X_valid, lmbda=lmbda)  # 学習データと同じ λ を使用

使いどころと落とし穴 #

変換後に平均 0・分散 1 を要求するモデルでは、Yeo-Johnson の後に StandardScaler を重ねると安定します(PowerTransformer は既定の standardize=True でこれを自動で行います)。\(\lambda\) の推定は学習用データのみで行い、検証・テストには同じ値を渡して情報漏洩を防ぎます。変換しても極端な外れ値の影響が残る場合は、RobustScaler のように中央値と IQR を使うスケーリングと組み合わせます。Yeo-Johnson 変換は正の値に限定される Box-Cox の代わりとして、0 や負の値を含む特徴量にそのまま使える前処理です。