sábado, 20 de agosto de 2016

Encontrar lambda de Box-Cox

El siguiente script calcula el valor lambda que hace que una variable, al ser elevada a este valor, tenga una distribucion mas cercana a una distribucion normal, segun tecnica Box-Cox. Esto con el objetivo de identificar cuales son las variables de un dataset que no tienen una distribución normal y que pueden transformarse para obtener mayor información de ellas.

NOTA: Este script es un ejemplo de busqueda, existe una funcion para esto en la librería scipy. Ver Referencia 1.

El script sigue estos paso:
1. carga el dataset boston.csv desde dropbox
2. crea la funcion is_not_normal que devuelve True si la asimetria de la variable es menor a -1 o mayor a 1, y si ademas el coeficiente de variacion (std/avg) es mayor a 1.
3. crea la funcion find_lambda que recibe el dataset en formato pandas.DataFrame y busca las variables que no son normales (usando la funcion is_not_normal) para luego imprimir los valores lambda de esas variables no normales.



Conceptualmente, la busqueda de el valor lambda seria así:

















las formas generales de exponentes son estas:










Para el dataset boston, una de las variables que no tiene una distribucion normal es crim,
y la salida del script seria algo así:





si graficamos la variable crim vs la crim^-0.05, queda así:














El excel con las imagenes se descarga AQUI


SCRIPT:
import numpy as np
import pandas as pd
from scipy.stats import skew

dataset = pd.read_csv('https://www.dropbox.com/s/raip96nwrifmpdd/boston.csv?dl=1')

""" IDENTIFICAR VARIABLE NO NORMAL """
def is_not_normal(x):
    asimetria = skew(x)
    coef_variacion  = np.std(x) / np.mean(x)
    if (-1 < asimetria > 1) and coef_variacion > 1:
        return True
    else:
        return False   

""" CALCULAR LAMBDA """
def find_lambda(df):
    for var in df:
        if is_not_normal(df[var]) == True and len(set(df[var])) > 10:
            for ii in [x for x in np.arange(-5,5,0.5) if x != 0]:
                std_old    = df[var].std()
                var_new    = df[var] ** (ii)
                var_new.replace([np.inf, -np.inf], np.nan,inplace=True)
                var_new.dropna(inplace=True)
                std_new    = var_new.std()
                print "variable:",var," lambda:",ii, " std_old:", std_old, " std_new:", std_new
            print'\n'

find_lambda(dataset)


Referencia:
2. Ejemplo similar en R: 
 http://apuntes-r.blogspot.com.ar/2016/03/transformar-variables-usando-box-cox.html




No hay comentarios:

Publicar un comentario