box-cox变换

参加kaggle比赛过程中,看到很多人在预处理阶段会对某些特征X做如下操作 Y = log(1+X), 说是可以把这个特征的分布正态化, 使其更加符合后面数据挖掘方法对数据分布的假设. 自己试了一下,有时的确可以提高准确度,有时却降低了准确度,很好奇其中的原理,遂在网上搜索了一番,整理如下.
Y = log(1+X)这个操作的真名应该时boxcox变换,用来降低X的skewness值,达到接近正态分布的目的. boxcox变换定义如下
参数 λ λ , 输入X,输出Y

ifλ!=0,Y=(Yλ1)/λ i f λ ! = 0 , Y = ( Y λ − 1 ) / λ

ifλ=0,Y=log(1+X) i f λ = 0 , Y = l o g ( 1 + X )

box-cox变换_第1张图片

上图lambda取不同值时, (X,Y)的曲线, boxcox变换的工作原理就在这些曲线的斜率中: 曲线斜率越大的区域,则对应区域的X变换后将被拉伸, 变换后这段区域的方差加大; 曲线斜率越小的区域, 对应区域的X变换后将被压缩, 变换后这段区域的方差变小.
右图中看出lambda = 0时, 取值较小的部分被拉伸, 取值较大的部分被压缩; lambda > 1时则相反. 所以boxcox变换的应用必须先分析输入X的分布是哪一种偏斜: X分布左偏,则应该应用lambda = 0的变换; X分布又偏,则应该应用lambda > 1的变换.

下图是一个左偏的例子
box-cox变换_第2张图片

本次实验代码

import os,sys,pdb
import numpy as np
import matplotlib.pyplot as plt
import math   
from scipy.stats import skew

X = [x/10.0 for x in range(100)]
plt.figure()
for p in range(0,4,1): 
    if p != 0:
        Y = (np.power(X,p) - 1) / p
    else:
        X = [x + 1 for x in X]
        Y = np.log(X)
    plt.subplot('22%d'%(p+1))
    plt.plot(X,Y)
    plt.title('lambda = %d'%p)
plt.suptitle('boxcox transform \n Y = (X^lambda - 1) / lambda if lambda != 0 \n Y = log(1+X) if labmda = 0')



X = [x/10.0 for x in range(100)]
plt.figure()
Y = []
for x in X:
    if x < 3:
        Y.append( math.exp(-(x-3)**2/(0.5) ) )
    else:
        Y.append( math.exp(-(x-3)**2/(20.0) ) )
plt.plot(X,Y,label='before transform skew=%f'%skew(Y))
Y = np.log(map( lambda y: y+1, Y))
#Y = map(lambda y: y**2-1, Y)
plt.plot(X,Y,label='after transform log(1+Y), skew=%f'%skew(Y))
plt.legend()




plt.show()

你可能感兴趣的:(math)