歪度(skewness、わいど)は、分布の「左右の非対称さ」を 1 つの数で表す指標である。平均 が分布の中心、分散標準偏差 が広がりを表すのに対して、歪度は「形のバランス」を表す。

  • 正の歪度(右に長い尾): 大半の値が小さく、少数の大きな値が裾を伸ばす。[平均](../mean/) > [中央値](../median/) になる傾向
  • 負の歪度(左に長い尾): 大半の値が大きく、少数の小さな値が裾を伸ばす。平均 < 中央値 になる傾向
  • 歪度 ≈ 0: 左右対称(正規分布など)

実用上は正の歪度を持つデータが多い。給与・取引金額・アクセス回数・待ち時間・株価のような「下限はあるが上限は無い」量は、構造的に右に裾を引きやすい。

定義と「なぜ 3 乗するか」

代表的な定義は「標準化された 3 次モーメント」である。

  • skewness = E[((X - mu) / sigma)^3]
  • mu は平均、sigma は標準偏差

3 乗を使うのは、左右の非対称性を符号付きで捉えるためである。差 (X - mu) をそのまま足し合わせると(1 乗)正と負が打ち消し合って常に 0 になる。差を 2 乗すると(分散 になる)符号が消えて広がりだけが残る。差を 3 乗すれば符号が保たれ、かつ大きく離れた値が強調される(差 2 → 8 倍, 差 -2 → -8 倍)。

(X - mu) / sigma のように標準偏差で割って標準化してから 3 乗するのは、無次元量にして単位やスケールに依存しない指標にするためである。これにより異なるデータ間で歪度の値を直接比較できるようになる。

歪度の絶対値の目安は次の通り。

  • |skewness| < 0.5: ほぼ対称
  • 0.5 ≤ |skewness| < 1.0: 中程度の歪み
  • |skewness| ≥ 1.0: 強い歪み(変換を検討する目安)

尖度との対比

歪度と並んで分布の形を測る指標に 尖度(kurtosis) がある。

  • 歪度(3 次モーメント): 左右の非対称さ
  • 尖度(4 次モーメント): 裾の重さ(中心の尖り方、外れ値の出やすさ)

正規分布の尖度は 3(または 0、定義による)。尖度が高いと「中心が尖って裾が重い」分布になり、外れ値が出やすい性質を持つ。歪度と尖度を組み合わせると、平均・分散だけでは見えない「分布の癖」が定量化できる。

前提・注意

  • 外れ値の影響を強く受ける(3 乗するので、極端な値が支配的になりやすい)
  • サンプル数が小さいと推定が不安定
  • 歪度は「形の傾向」を示すだけで、分布の全体像を代替しない。ヒストグラムや KDE で形を目視するのが先決
  • 多峰性(山が複数)の判断はできない

log1p (plus) 変換

log1p 変換は log(1 + x) を適用する変換。右に歪んだ分布(長い右尾)を圧縮し、極端な値の影響を和らげるのが目的である。log(x)x=0 で定義できないため、0 を含むデータでは扱いにくい。log1plog(1 + x) を使うことで 0 を含めても安全に変換でき、x が小さいときは log(1 + x) ≈ x となるため、値の歪みを抑えつつ自然にスケールを圧縮できる。


使いどころ

  • 取引金額やアクセス回数など、右に長い分布の特徴量
  • 外れ値の影響を抑えたいとき
  • 変数のスケール差が大きく、学習が不安定なとき

注意点

  • x >= 0 が前提(負の値には直接使えない)
  • 0 を含む場合でも log1p なら安全に扱える
  • 変換後の解釈(単位)が変わる点に注意

Python での実例

import numpy as np
import matplotlib.pyplot as plt

rng = np.random.default_rng(0)
raw = rng.lognormal(mean=1.0, sigma=0.8, size=1000)
log1p = np.log1p(raw)

fig, axes = plt.subplots(1, 2, figsize=(8, 3))
axes[0].hist(raw, bins=30, color="#4C78A8", edgecolor="white")
axes[0].set_title("Original (right-skewed)")
axes[1].hist(log1p, bins=30, color="#F58518", edgecolor="white")
axes[1].set_title("After log1p")
plt.tight_layout()
plt.show()

出力:

skewness_log1p

右歪み・対称・左歪みの並列比較

歪度の符号と分布形の対応を、3 種類のデータで並べて見る。

from scipy import stats

right = rng.lognormal(0.0, 0.6, 5000)
sym = rng.normal(2.0, 0.8, 5000)
left = -rng.lognormal(0.0, 0.6, 5000) + np.exp(2)
for name, data in [("right", right), ("sym", sym), ("left", left)]:
    print(f"{name}: skew={stats.skew(data):+.2f}, mean={data.mean():.2f}, median={np.median(data):.2f}")
plt.savefig("skewness_sign_compare.svg", bbox_inches="tight")

出力:

right: skew=+2.05, mean=1.27, median=1.01
sym:   skew=+0.00, mean=2.00, median=2.00
left:  skew=-2.05, mean=6.12, median=6.38

右歪み・対称・左歪みでの mean と median の位置

3 つのヒストグラムで、赤線が平均、緑線が中央値である。右歪み(左図)では平均が中央値より右にあり、対称(中央)では一致、左歪み(右図)では平均が中央値より左にある、というのが歪度の符号と直接対応している。「平均と中央値のどちらが大きいか」という素朴な観察だけでも、歪みの方向がある程度判定できる。

回帰の残差プロットで効く log 変換

右に歪んだ目的変数をそのまま線形回帰すると、残差が予測値の大きさに比例して広がる「ファン型」になりがちで、線形回帰の仮定(残差の等分散性)が崩れる。log1p(y) で学習してから expm1 で戻すと、残差が均一に近づく。

from sklearn.linear_model import LinearRegression

area = rng.uniform(30, 200, 300)
price = np.exp(1.0 + 0.015 * area + rng.normal(0, 0.25, 300))  # right-skewed
X = area.reshape(-1, 1)
ols_raw = LinearRegression().fit(X, price)
ols_log = LinearRegression().fit(X, np.log1p(price))
# 詳細は scripts 側を参照
plt.savefig("skewness_residual_diag.svg", bbox_inches="tight")

生の y で学習すると残差がファン型、log1p 変換で均一に

上段が生の y での回帰と残差プロット、下段が log1p(y) での回帰と残差プロット。右上の残差は予測値が大きい右側で大きく広がる「ファン型」をしているのに対し、右下の log1p 後の残差は予測値全域で一様に近い形になっている。残差が等分散になると、信頼区間・予測区間の解釈が安定し、勾配ブースティング以外の線形・正則化系モデルの予測性能が改善することが多いと考えられる。

なお木系モデル(ランダムフォレスト・勾配ブースティング)は分割点の順序しか見ないため、目的変数の変換による予測性能の改善はほとんど無い場合が多い。歪度補正は線形モデル・距離ベース・ベイズモデルで主に効く前処理となる。


数学での使いどころ

  • 分布の形状把握(非対称性の定量化)
  • 正規性の仮定チェックの補助指標

機械学習での使いどころ

歪度の高い特徴量は、線形モデルや距離ベースのモデルで学習を不安定にしやすい。前処理として変換を入れる判断に歪度を使う。

  • 特徴量の分布形状の把握(EDA で歪度をスキャンして変換対象を絞る)
  • log1p 変換・Box-Cox 変換の判断: |skewness| > 1 程度が目安
  • 線形回帰・LogisticRegression の入力前処理: 右に長い特徴量を圧縮して残差の歪みを減らす
  • 目的変数の前処理: 価格予測などで目的変数が右に歪んでいる場合、log1p(y) で学習してから expm1(y_pred) で戻す
  • 異常検知での「正常分布からの逸脱度」評価
  • 木系モデル(RandomForest, 勾配ブースティング)では順序判定なので歪度の影響は小さく、変換不要なことが多い

具体的な利用例:

  • 不動産価格予測で価格が右に長く skewness ≈ 1.5log1p(price) を目的変数にして学習
  • 待ち時間予測で skewness ≈ 2.0 → Box-Cox 変換で λ を最適化して正規化
  • 顧客生涯価値(LTV)の予測で右に長い分布を log1p で圧縮

適さないケース

  • 負の値を多く含む変数(別の変換が必要)
  • 変換後の解釈が重要な場面(ログ変換で意味が変わる)