domingo, 16 de abril de 2017

Creación de variables de grupo

Si se tiene un dataset para predecir una clase, y dentro de las variables existen algunas que son discretas (como ciudad, empresa, rubro, etc), puede usarse esta variable discreta para crear nuevas variables "dummies" que agrupen los valores que mejor ajusten la clase a predecir.

En este ejemplo se transforma la variable discreta "state" para crear una matriz dispersa con valores dummies, luego se ajusta un modelo usando el algoritmo ExtraTreesClassifier para predecir la clase "churn". Después de tener el modelo se extrae la importancia de las variables para identificar (usando percentiles) las nuevas variables dummies a crear.

Nota: Para la importancia de la variable, el algoritmo ExtraTreesClassifier usa la medida "Mean Decrease Impurity Importance", también llamado "Gini importance", "Mean Decrease Gini", etc. Para detalles, ver Referencia No.1. Para detalles sobre sesgos en el calculo de la importancia, ver Referencia No.2. Para ver las imágenes, estas se pueden descargar AQUI


El proceso conceptual sigue estos pasos:

PASO 1
Cargar el dataset que contiene la variable a predecir (churn en este caso) y la variable discreta a descomponer. Seria algo así:
















PASO 2
Transoformar variable discreata en matriz dispersa, usando la función get_dummies de la librería pandas, quedando así:







PASO 3
Se ajusta un modelo para predecir la variable "churn", usando a la matriz dispersa. En este ejemplo se aplica el algoritmo ExtraTreesClassifier, únicamente para extraer la importancia de las variables:










PASO 4
Se dividen las variables según su importancia usando percentiles, para luego crear los script que crean los grupos, segun el lenguaje que se este usando:


















El script seria este:
import pandas as pd
import numpy as np 
from sklearn.ensemble import ExtraTreesClassifier 

# FUNCIONES
# ---------------------------------------------------------------------
def float_to_int(df):
    for col in df.columns:
      if np.issubdtype(df[col].dtype, np.number):
        df[col] = df[col].fillna(0.0).astype(int)
    return df 

def discrete_to_matrix(df=None, var_name=None, class_name=None):
   bin_mtx = pd.get_dummies(df[var_name])
   bin_class = df[class_name]
   return bin_mtx, bin_class

def var_importance(bin_mtx=None,bin_class=None, n_tree=10): 
   modelo = ExtraTreesClassifier(n_estimators = n_tree)
   modelo.fit(bin_mtx, bin_class)
   var_imp = pd.DataFrame({
    'feature': bin_mtx.columns.values.tolist(),
    'v_importance' : modelo.feature_importances_.tolist()})
   var_imp = var_imp.sort_values(by = 'v_importance', ascending=False)
   return var_imp


def print_group(umbrales=None, var_imp=None, var_name=None,output_type='sql_query'):
  comment_chr = {'sql_query':'-- ','qlik_query':'// ','pandas_query':'# ','r_query':'# '}

  for k, v in enumerate(umbrales):
    if v == max(umbrales):
      p_max = 1
      val_max = var_imp['v_importance'].quantile(p_max) + 0.00001
    else:
      p_max = umbrales[k+1]
      val_max = var_imp['v_importance'].quantile(p_max)

    val_min = var_imp['v_importance'].quantile(umbrales[k])
    gx = var_imp[(var_imp['v_importance']>=val_min) & (var_imp['v_importance'] < val_max)].iloc[:,0]
    gx = gx.tolist()

    if k==0: 
      print(comment_chr[output_type], output_type.upper(), var_name.upper())

    print(comment_chr[output_type],'desde: ',round(val_min,4),' hasta: ',round(val_max,4),' rango: ',round(val_max - val_min,4))

    if output_type == 'sql_query':
      print('(case when '+var_name+' in (\'' + '\',\''.join(map(str, gx)) + '\''') then 1 else 0 end) as grupo'+str(k+1)+',')
    elif output_type == 'qlik_query':
      print('If (match('+var_name+',\'' + '\',\''.join(map(str, gx)) + '\'''),1,0) as '+var_name+'_grupo'+str(k+1)+',')
    elif output_type == 'pandas_query':
      print('df[\'grupo'+str(k+1)+'\'] = np.where(df.'+var_name+'.isin([\'' + '\',\''.join(map(str, gx)) + '\''']),1,0)')
    elif output_type == 'r_query':
      print('df$grupo'+str(k+1)+' <- ifelse(df$'+var_name+' %in% c(\'' + '\',\''.join(map(str, gx)) + '\'''),1,0)')


if __name__ == '__main__':
  # PASO 1 
  #cargar data set y definir constantes
  df = pd.read_csv('https://www.dropbox.com/s/ed4j8l550zdy78j/churn3.csv?dl=1')
  var_name  = 'state'
  class_name  = 'churn'
  umbrales = [0.70,0.80,0.90,0.98]

  # PASO 2 
  # Transformar variable de discreta a matriz dispersa
  df = float_to_int(df)
  bin_mtx, bin_class = discrete_to_matrix(df=df, var_name=var_name, class_name=class_name)

  # PASO 3
  # Crear importancia devariables
  var_imp = var_importance(bin_mtx=bin_mtx,bin_class=bin_class, n_tree=50)

  # PASO 4 
  # imprime query de grupos
  print_group(var_imp=var_imp, var_name=var_name, umbrales=umbrales, output_type='qlik_query')
  print_group(var_imp=var_imp, var_name=var_name, umbrales=umbrales, output_type='sql_query')
Referencias
1. http://papers.nips.cc/paper/4928-understanding-variable-importances-in-forests-of-randomized-trees.pdf
2. http://blog.datadive.net/selecting-good-features-part-iii-random-forests/










No hay comentarios:

Publicar un comentario