sklearn の PowerTransformer を使って yeo-johnson 変換を行うメソッドです。yeo-johnson 変換により分布が正規分布に近づきます。yeo-johnson変換を使用する際の参考にどうぞ。
-
yeo-johnson 変換による歪度・尖度の絶対値の減少量を表示する様にしてあります。歪度・尖度はどちらも正規分布で0になるので、yeo-johnson 変換によりどのくらい正規分布に近づいたかの指標になります。
-
yeo-johnson 変換を行う前に MinMaxScaler で正規化(最小値0、最大値1に変換)しています。これをしておかないと、
np.random.randn(30) / 100 + 10
という様に、分散が小さく平均が大きい標本でRuntimeWarning: divide by zero encountered in log
という warning が出ます。(結果が全て同じ値になったりします。) 参考:https://github.com/scikit-learn/scikit-learn/issues/14959#issuecomment-602090088
import pandas as pd
def yeojohnson(df):
# 参照渡しされるので新規のものに変えておく
df = df.copy()
# 比較用に残しておく
df_orig = df.copy()
# yeo-johnson
# 標準化は別にしても良い(standardize=Trueにしても良い)
# mmなしだと、エラーが出たりするので先にやっておく
# 参考:https://github.com/scikit-learn/scikit-learn/issues/14959#issuecomment-574253115
# 参考:https://github.com/scikit-learn/scikit-learn/issues/14959#issuecomment-602090088
from sklearn.preprocessing import MinMaxScaler, PowerTransformer
mm = MinMaxScaler()
pt = PowerTransformer(standardize=False)
df[:] = mm.fit_transform(df[:])
df[:] = pt.fit_transform(df[:])
# 歪度・尖度を計算
# 歪度:負:左長裾、0:正規分布、正:右長裾
# 尖度:負:平、0:正規分布、正:凸
# なので絶対値の差を見る
df_diff = pd.concat([
df_orig.skew(),
df.skew(),
df_orig.skew().abs() - df.skew().abs(),
df_orig.kurtosis(),
df.kurtosis(),
df_orig.kurtosis().abs() - df.kurtosis().abs(),
], axis=1)
df_diff.columns=[
'skew (original)',
'skew (yeo-johnson)',
'skew abs decrease',
'kurtosis (original)',
'kurtosis (yeo-johnson)',
'kurtosis abs decrease',
]
display(df_diff)
return df
# 使用例
from sklearn.datasets import load_iris
iris = load_iris(as_frame=True)['data']
yeojohnson(iris)
出力(歪度・尖度の減少量):