対数変換が適さない場合がある!?対数変換すると結果が悪くなる例の紹介

対数変換が適さない場合がある!?対数変換すると結果が悪くなる例の紹介


前回に続き、変数変換のお話です。
KaggleのKernelや諸々のブログで紹介されている手法を見ていて(自分が使う手法も含めて)ふと疑問を感じたことがあってこの記事を書きました。
それは、数値変数(連続値をとる変数)が正規分布に従わない場合に、対数変換によって正規分布に擬似的に従わせたうえでモデルを作っていることです。
正規分布に従わない連続値を対数変換するとよくわからないけど正規分布に従うと信じていますが、これが当てはまらない例ってなんだろうと思い調べてみました。

正規分布に従わせるための対数変換

連続値を対象にしたモデルの多くは正規分布を仮定しています。
しかし、現実われわれが直面するデータをみるとわかるように、きれいに正規分布している場合はほとんどないと思います。
とは言うものの、なんとか無理やり正規分布に近似させたい。
そんな場合に対数変換が用いられます。

もし、もとのデータが対数正規分布にしたがっているならば、対数変換後のデータは正規分布に従います。
この場合、対数変換によってデータの歪度を取り除くことができたと言えます。
しかし、あるケースにおいては対数変換によって、もとのデータの分布がより歪んでしまう場合もあります。
以下の式で表される \( x_{i} \) の分布を考えます。
$$ x_{i} = 100 \times \left( e^{\mu_{i}} – 1 \right) + 1 $$
ただし、 \( \mu_{i} \sim U(0,1) \) とし、 \( \mu_{i} \) は0から1の一様分布に従うとします。
\( n =10000 \)としたときの \( x_{i} \) を打点し、分布を確かめます。
input:

歪度が1を超えており、この分布は正規分布に従っているとは言えません。
さて、この連続値に対して対数変換によって正規分布に近似できるかを確かめます。
\( y_{i} \) は \( x_{i} \) を以下のように対数変換した変数です。
$$ y_{i} = \log (x_{i}) $$
同じく \( n =10000 \) としたときの \( y_{i} \) の分布を確かめます。
input:

output:

かなり右に裾野が伸びていて、 \( x_{i} \) と同様に正規分布に従うとは言えなさそうです。
さらに歪度を比較すると、 \( x_{i} \) よりも \( y_{i} \) の方が絶対値が大きく、対数変換によってより分布が歪む結果となりました。

もし、もとのデータが対数正規分布に従がっているのであれば、対数変換により正規分布に近似できます。
しかし、もとのデータが対数正規分布に従っていない場合は、対数変換によりさらに歪度が増大し、正規分布から離れてしまうのです。

分散を減少させるための対数変換

対数変換はデータを正規分布に従わせる以外にも、外れ値が含まれるデータの分散を小さくするためにも使われます。
しかし、ケースによっては対数変換によって分散が増大してしまうこともあります。

以下で表される \( y_{i} \) の分散を考えます。
$$ y_{i} = \beta_{0} + \epsilon_{i} $$
ただし、 \( \beta_{0} \) は定数で、 \( \epsilon_{i} \sim U(-0.5,0.5) \) とし、 \( \epsilon_{i} \) は-0.5から0.5の一様分布に従うとします。
ここで \( n=100 \) 回 \( y_i \) をサンプリングし、もとの \( y_{i} \) と対数変換の \( \log y_{i} \) に最小二乗法を適用し、標準誤差 \( \sigma \) を求めます。

ここで標準誤差の推定で偏りを小さくするため、1,000回モンテカルロシミュレーションをします。
input:

output:

\( \beta \) が小さいときは元のモデルの方が標準誤差が小さいですが、 \( \beta \) が2を超えたあたりから対数変換後の方が標準偏差が小さくなります。

次に6,4,8,10という外れ値を加えた場合の、もとのモデルと対数変換後のモデルの標準偏差を比較する。
input:

output:

外れ値の有無に関わらず、ほぼ同一の挙動をしていると言えそうです。
\( \beta \) が大きい、つまり平均値が大きい場合は対数変換によって分散(標準偏差)が小さくなり、 \( \beta \) が小さい、つまり平均値が小さい場合は対数変換は分散を増大させています。

まとめ

今まで見てきたように、場合によっては対数変換をしても正規分布に従わなかったり(歪度を減少させる)、分散が増大したりするケースがあることがわかりました。
Pythonで実装するならnumpyのlog1p()、log()メソッドなど
とは言え、対数変換はお手軽に実装できるので、まずは対数変換を試してみるという手は間違いではないでしょう。
重要なのは、対数変換でもうまくいかない場合があることを知っておくことだと思います。