Clasificación binaria de TensorFlow: ejemplo de clasificador lineal

Los dos mas comunes aprendizaje supervisado Las tareas son regresión lineal y clasificador lineal. La regresión lineal predice un valor mientras que el clasificador lineal predice una clase. Este tutorial se centra en clasificadores lineales.

¿Qué es el clasificador lineal?

A Clasificador lineal En Machine Learning es un método para encontrar la clase de un objeto en función de sus características para la clasificación estadística. Toma decisiones de clasificación basadas en el valor de una combinación lineal de características de un objeto. El clasificador lineal se utiliza en problemas prácticos como la clasificación de documentos y problemas que tienen muchas variables.

Los problemas de clasificación representan aproximadamente el 80 por ciento de la tarea de aprendizaje automático. La clasificación tiene como objetivo predecir la probabilidad de cada clase dado un conjunto de entradas. La etiqueta (es decir, la variable dependiente) es un valor discreto, llamado clase.

  1. Si la etiqueta tiene sólo dos clases, el algoritmo de aprendizaje es un clasificador binario.
  2. El clasificador multiclase aborda etiquetas con más de dos clases.

Por ejemplo, un problema típico de clasificación binaria es predecir la probabilidad de que un cliente realice una segunda compra. Predecir el tipo de animal que aparece en una imagen es un problema de clasificación multiclase, ya que existen más de dos variedades de animales.

La parte teórica de este tutorial se centra principalmente en la clase binaria. Aprenderá más sobre la función de salida multiclase en un tutorial futuro.

¿Cómo funciona el clasificador binario?

En el tutorial anterior aprendiste que una función se compone de dos tipos de variables, una variable dependiente y un conjunto de características (variables independientes). En la regresión lineal, una variable dependiente es un número real sin rango. El objetivo principal es predecir su valor minimizando el error cuadrático medio.

Para el clasificador binario de TensorFlow, la etiqueta puede haber tenido dos valores enteros posibles. En la mayoría de los casos, es [0,1] o [1,2]. Por ejemplo, el objetivo es predecir si un cliente comprará un producto o no. La etiqueta se define de la siguiente manera:

  • Y = 1 (el cliente compró el producto)
  • Y = 0 (el cliente no compra el producto)

El modelo utiliza las características X para clasificar a cada cliente en la clase más probable a la que pertenece, es decir, comprador potencial o no.

La probabilidad de éxito se calcula con regresión logística. El algoritmo calculará una probabilidad basada en la característica X y predice un éxito cuando esta probabilidad sea superior al 50 por ciento. Más formalmente, la probabilidad se calcula como se muestra en el siguiente ejemplo de clasificación binaria de TensorFlow:

Ejemplo de clasificación binaria

donde 0 es el conjunto de pesos, las características y b el sesgo.

La función se puede descomponer en dos partes:

  • El modelo lineal
  • La función logística

Modelo lineal

Ya estás familiarizado con la forma en que se calculan los pesos. Los pesos se calculan mediante un producto escalar:Producto de punto Y es una función lineal de todas las características xi. Si el modelo no tiene características, la predicción es igual al sesgo, b.

Los pesos indican la dirección de la correlación entre las características xi y la etiqueta y. Una correlación positiva aumenta la probabilidad de la clase positiva, mientras que una correlación negativa acerca la probabilidad a 0 (es decir, clase negativa).

El modelo lineal devuelve sólo números reales, lo cual es inconsistente con la medida de probabilidad del rango [0,1]. La función logística es necesaria para convertir la salida del modelo lineal en una probabilidad,

función logística

La función logística, o función sigmoidea, tiene forma de S y la salida de esta función siempre está entre 0 y 1.

Ejemplo de función logística

Ejemplo de función logística
Ejemplo de función logística

Es fácil sustituir el resultado de la regresión lineal en la función sigmoidea. Da como resultado un nuevo número con una probabilidad entre 0 y 1.

El clasificador puede transformar la probabilidad en una clase.

  • Los valores entre 0 y 0.49 pasan a ser clase 0
  • Los valores entre 0.5 y 1 pasan a ser clase 1

¿Cómo medir el rendimiento del clasificador lineal?

Exactitud

El rendimiento general de un clasificador se mide con la métrica de precisión. Precisión recoge todos los valores correctos divididos por el número total de observaciones. Por ejemplo, un valor de precisión del 80 por ciento significa que el modelo es correcto en el 80 por ciento de los casos.

Métrica de precisión
Mida el rendimiento del clasificador lineal utilizando la métrica de precisión

Se puede observar una deficiencia con esta métrica, especialmente para la clase de desequilibrio. Un conjunto de datos desequilibrado se produce cuando el número de observaciones por grupo no es igual. Digamos que intenta clasificar un evento raro con una función logística. Imagine que el clasificador intenta estimar la muerte de un paciente después de una enfermedad. En los datos, el 5 por ciento de los pacientes fallece. Puede entrenar un clasificador para predecir el número de muertes y utilizar la métrica de precisión para evaluar el rendimiento. Si el clasificador predice 0 muertes para todo el conjunto de datos, será correcto en el 95 por ciento de los casos.

Matriz de confusión

Una mejor manera de evaluar el desempeño de un clasificador es observar la matriz de confusión.

Matriz de confusión
Mida el rendimiento del clasificador lineal utilizando la matriz de confusión

La matriz de confusión Visualiza la precisión de un clasificador comparando las clases reales y previstas, como se muestra en el ejemplo de clasificador lineal anterior. La matriz de confusión binaria está compuesta por cuadrados:

  • TP: Verdadero positivo: valores pronosticados correctamente como positivos reales
  • FP: Los valores pronosticados predijeron incorrectamente un positivo real. es decir, valores negativos predichos como positivos
  • FN: Falso Negativo: Valores positivos predichos como negativos
  • TN: Verdadero negativo: los valores pronosticados se predijeron correctamente como negativos reales

A partir de la matriz de confusión, es fácil comparar la clase real y la clase prevista.

Precisión y sensibilidad

La matriz de confusión proporciona una buena idea del verdadero positivo y del falso positivo. En algunos casos, es preferible tener una métrica más concisa.

Precisión

La métrica de precisión muestra la exactitud de la clase positiva. Mide la probabilidad de que la predicción de la clase positiva sea correcta.

Precisión

La puntuación máxima es 1 cuando el clasificador clasifica perfectamente todos los valores positivos. La precisión por sí sola no es muy útil porque ignora la clase negativa. La métrica suele estar emparejada con la métrica de recuperación. La recuperación también se llama sensibilidad o tasa de verdaderos positivos.

Sensibilidad

La sensibilidad calcula la proporción de clases positivas detectadas correctamente. Esta métrica indica qué tan bueno es el modelo para reconocer una clase positiva.

Sensibilidad

Clasificador lineal con TensorFlow

Para este tutorial, usaremos el conjunto de datos del censo. El propósito es utilizar las variables del conjunto de datos del censo para predecir el nivel de ingresos. Tenga en cuenta que el ingreso es una variable binaria.

  • con un valor de 1 si el ingreso > 50k
  • 0 si ingresos < 50k.

Esta variable es tu etiqueta.

Este conjunto de datos incluye ocho variables categóricas:

  • lugar de trabajo
  • educación
  • marital
  • Ocupación.
  • relación
  • raza
  • vie
  • patria

además, seis variables continuas:

  • edad
  • fnlwgt
  • núm_educación
  • ganancia capital
  • perdida de capital
  • horas_semana

A través de este ejemplo de Clasificación de TensorFlow, comprenderá cómo entrenar clasificadores lineales de TensorFlow con el estimador de TensorFlow y cómo mejorar la métrica de precisión.

Procederemos de la siguiente manera:

  • Paso 1) Importar los datos
  • Paso 2) Conversión de datos
  • Paso 3) Entrenar al clasificador
  • Paso 4) Mejorar el modelo
  • Paso 5) Hiperparámetro: Lazo y Ridge

Paso 1) Importar los datos

Primero importe las bibliotecas utilizadas durante el tutorial.

import tensorflow as tf
import pandas as pd

A continuación, importe los datos del archivo de UCI y defina los nombres de las columnas. Utilizará COLUMNAS para nombrar las columnas en un marco de datos de pandas.

Tenga en cuenta que entrenará el clasificador utilizando un marco de datos de Pandas.

## Define path data
COLUMNS = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital',
           'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss',
           'hours_week', 'native_country', 'label']
PATH = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data"
PATH_test = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.test"

Los datos almacenados en línea ya se dividen entre un conjunto de trenes y un conjunto de pruebas.

df_train = pd.read_csv(PATH, skipinitialspace=True, names = COLUMNS, index_col=False)
df_test = pd.read_csv(PATH_test,skiprows = 1, skipinitialspace=True, names = COLUMNS, index_col=False)

El conjunto de trenes contiene 32,561 observaciones y el conjunto de pruebas 16,281.

print(df_train.shape, df_test.shape)
print(df_train.dtypes)
(32561, 15) (16281, 15)
age                int64
workclass         object
fnlwgt             int64
education         object
education_num      int64
marital           object
occupation        object
relationship      object
race              object
sex               object
capital_gain       int64
capital_loss       int64
hours_week         int64
native_country    object
label             object
dtype: object

Tensorflow requiere un valor booleano para entrenar al clasificador. Debe convertir los valores de cadena a entero. La etiqueta se almacena como un objeto, sin embargo, debe convertirla en un valor numérico. El código a continuación crea un diccionario con los valores para convertir y realiza un bucle sobre el elemento de la columna. Tenga en cuenta que realiza esta operación dos veces, una para la prueba de entrenamiento y otra para el conjunto de pruebas.

label = {'<=50K': 0,'>50K': 1}
df_train.label = [label[item] for item in df_train.label]
label_t = {'<=50K.': 0,'>50K.': 1}
df_test.label = [label_t[item] for item in df_test.label]

En los datos del tren hay 24,720 rentas inferiores a 50k y 7841 superiores. La proporción es casi la misma para el conjunto de prueba. Consulte este tutorial sobre Facetas para obtener más información.

print(df_train["label"].value_counts())
### The model will be correct in atleast 70% of the case
print(df_test["label"].value_counts())
## Unbalanced label
print(df_train.dtypes)
0    24720
1     7841
Name: label, dtype: int64
0    12435
1     3846
Name: label, dtype: int64
age                int64
workclass         object
fnlwgt             int64
education         object
education_num      int64
marital           object
occupation        object
relationship      object
race              object
sex               object
capital_gain       int64
capital_loss       int64
hours_week         int64
native_country    object
label              int64
dtype: object

Paso 2) Conversión de datos

Se requieren algunos pasos antes de entrenar un clasificador lineal con Tensorflow. Debe preparar las características que se incluirán en el modelo. En la regresión de referencia, utilizará los datos originales sin aplicar ninguna transformación.

El estimador debe tener una lista de características para entrenar el modelo. Por lo tanto, los datos de la columna deben convertirse en un tensor.

Una buena práctica es definir dos listas de características según su tipo y luego pasarlas en las columnas de características del estimador.

Comenzará convirtiendo características continuas y luego definirá un depósito con los datos categóricos.

Las características del conjunto de datos tienen dos formatos:

  • Entero
  • Objeto

Cada característica se enumera en las siguientes dos variables según sus tipos.

## Add features to the bucket: 
### Define continuous list
CONTI_FEATURES  = ['age', 'fnlwgt','capital_gain', 'education_num', 'capital_loss', 'hours_week']
### Define the categorical list
CATE_FEATURES = ['workclass', 'education', 'marital', 'occupation', 'relationship', 'race', 'sex', 'native_country']

Feature_column está equipada con un objeto numeric_column para ayudar en la transformación de las variables continuas en tensor. En el siguiente código, convierte todas las variables de CONTI_FEATURES en un tensor con un valor numérico. Esto es obligatorio para construir el modelo. Todas las variables independientes deben convertirse al tipo adecuado de tensor.

A continuación escribimos un código para permitirle ver lo que sucede detrás de feature_column.numeric_column. Imprimiremos el valor convertido para la edad. Tiene fines explicativos, por lo que no es necesario comprender el código Python. Puede consultar la documentación oficial para comprender los códigos.

def print_transformation(feature = "age", continuous = True, size = 2): 
    #X = fc.numeric_column(feature)
    ## Create feature name
    feature_names = [
    feature]

    ## Create dict with the data
    d = dict(zip(feature_names, [df_train[feature]]))

    ## Convert age
    if continuous == True:
        c = tf.feature_column.numeric_column(feature)
        feature_columns = [c]
    else: 
        c = tf.feature_column.categorical_column_with_hash_bucket(feature, hash_bucket_size=size) 
        c_indicator = tf.feature_column.indicator_column(c)
        feature_columns = [c_indicator]
    
## Use input_layer to print the value
    input_layer = tf.feature_column.input_layer(
        features=d,
        feature_columns=feature_columns
        )
    ## Create lookup table
    zero = tf.constant(0, dtype=tf.float32)
    where = tf.not_equal(input_layer, zero)
    ## Return lookup tble
    indices = tf.where(where)
    values = tf.gather_nd(input_layer, indices)
    ## Initiate graph
    sess = tf.Session()
    ## Print value
    print(sess.run(input_layer))
print_transformation(feature = "age", continuous = True) 
[[39.]
 [50.]
 [38.]
 ...
 [58.]
 [22.]
 [52.]]

Los valores son exactamente los mismos que en df_train

continuous_features = [tf.feature_column.numeric_column(k) for k in CONTI_FEATURES]

Según la documentación de TensorFlow, existen diferentes formas de convertir datos categóricos. Si se conoce la lista de vocabulario de una característica y no tiene muchos valores, es posible crear la columna categórica con categorical_column_with_vocabulary_list. Asignará una identificación a toda la lista de vocabulario única.

Por ejemplo, si el estado de una variable tiene tres valores distintos:

  • Esposo
  • Esposa
  • Individual

Entonces se atribuirán tres identificaciones. Por ejemplo, el marido tendrá el ID 1, la esposa el ID 2 y así sucesivamente.

Con fines ilustrativos, puede utilizar este código para convertir una variable de objeto en una columna categórica en TensorFlow.

La característica sexo solo puede tener dos valores: masculino o femenino. Cuando convertimos la característica sexo, Tensorflow creará dos columnas nuevas, una para masculino y otra para femenino. Si el sexo es masculino, la nueva columna masculino será igual a 2 y la femenina a 1. Este ejemplo se muestra en la siguiente tabla:

filas vie después de la transformación varón hembra
1 varón => 1 0
2 varón => 1 0
3 hembra => 0 1

En flujo tensor:

print_transformation(feature = "sex", continuous = False, size = 2)
[[1. 0.]
 [1. 0.]
 [1. 0.]
 ...
 [0. 1.]
 [1. 0.]
 [0. 1.]]

relationship = tf.feature_column.categorical_column_with_vocabulary_list(
    'relationship', [
        'Husband', 'Not-in-family', 'Wife', 'Own-child', 'Unmarried',
        'Other-relative'])

A continuación agregamos Python código para imprimir la codificación. Nuevamente, no es necesario comprender el código, el propósito es ver la transformación.

Sin embargo, una forma más rápida de transformar los datos es utilizar el método categorical_column_with_hash_bucket. Será útil alterar las variables de cadena en una matriz dispersa. Una matriz dispersa es una matriz con mayoritariamente cero. El método se encarga de todo. Solo necesita especificar la cantidad de depósitos y la columna de clave. La cantidad de depósitos es la cantidad máxima de grupos que Tensorflow puede crear. La columna clave es simplemente el nombre de la columna a convertir.

En el código siguiente, crea un bucle sobre todas las características categóricas.

categorical_features = [tf.feature_column.categorical_column_with_hash_bucket(k, hash_bucket_size=1000) for k in CATE_FEATURES]

Paso 3) Entrenar al Clasificador

TensorFlow proporciona actualmente un estimador para la regresión lineal y la clasificación lineal.

  • Regresión lineal: LinearRegressor
  • Clasificación lineal: LinearClassifier

La sintaxis del clasificador lineal es la misma que en el tutorial sobre regresión lineal excepto por un argumento, n_class. Debe definir la columna de características, el directorio del modelo y compararlo con el regresor lineal; tienes que definir el número de clase. Para una regresión logit, el número de clases es igual a 2.

El modelo calculará los pesos de las columnas contenidas encontinuous_features y categorical_features.

model = tf.estimator.LinearClassifier(
    n_classes = 2,
    model_dir="ongoing/train", 
    feature_columns=categorical_features+ continuous_features)

Salida

INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'ongoing/train', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': 
<tensorflow.python.training.server_lib.ClusterSpec object at 0x181f24c898>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}

Ahora que el clasificador está definido, puede crear la función de entrada. El método es el mismo que en el tutorial del regresor lineal. Aquí, utiliza un tamaño de lote de 128 y mezcla los datos.

FEATURES = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country']
LABEL= 'label'
def get_input_fn(data_set, num_epochs=None, n_batch = 128, shuffle=True):
    return tf.estimator.inputs.pandas_input_fn(
       x=pd.DataFrame({k: data_set[k].values for k in FEATURES}),
       y = pd.Series(data_set[LABEL].values),
       batch_size=n_batch,   
       num_epochs=num_epochs,
       shuffle=shuffle)

Crea una función con los argumentos requeridos por el estimador lineal, es decir, número de épocas, número de lotes y mezcla el conjunto de datos o la nota. Ya que usas el pandas método para pasar los datos al modelo, debe definir las variables X como un marco de datos de pandas. Tenga en cuenta que recorre todos los datos almacenados en FUNCIONES.

Entrenemos el modelo con el objeto model.train. Utilice la función previamente definida para alimentar el modelo con los valores apropiados. Tenga en cuenta que configuró el tamaño del lote en 128 y el número de épocas en Ninguno. El modelo será entrenado en mil pasos.

model.train(input_fn=get_input_fn(df_train, 
                                      num_epochs=None,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)
									 
INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow: Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into ongoing/train/model.ckpt.
INFO:tensorflow:loss = 88.722855, step = 1
INFO:tensorflow:global_step/sec: 65.8282
INFO:tensorflow:loss = 52583.64, step = 101 (1.528 sec)
INFO:tensorflow:global_step/sec: 118.386
INFO:tensorflow:loss = 25203.816, step = 201 (0.837 sec)
INFO:tensorflow:global_step/sec: 110.542
INFO:tensorflow:loss = 54924.312, step = 301 (0.905 sec)
INFO:tensorflow:global_step/sec: 199.03
INFO:tensorflow:loss = 68509.31, step = 401 (0.502 sec)
INFO:tensorflow:global_step/sec: 167.488
INFO:tensorflow:loss = 9151.754, step = 501 (0.599 sec)
INFO:tensorflow:global_step/sec: 220.155
INFO:tensorflow:loss = 34576.06, step = 601 (0.453 sec)
INFO:tensorflow:global_step/sec: 199.016
INFO:tensorflow:loss = 36047.117, step = 701 (0.503 sec)
INFO:tensorflow:global_step/sec: 197.531
INFO:tensorflow:loss = 22608.148, step = 801 (0.505 sec)
INFO:tensorflow:global_step/sec: 208.479
INFO:tensorflow:loss = 22201.918, step = 901 (0.479 sec)
INFO:tensorflow:Saving checkpoints for 1000 into ongoing/train/model.ckpt.
INFO:tensorflow:Loss for final step: 5444.363.

<tensorflow.python.estimator.canned.linear.LinearClassifier at 0x181f223630>

Tenga en cuenta que la pérdida disminuyó posteriormente durante los últimos 100 pasos, es decir, de 901 a 1000.

La pérdida final después de mil iteraciones es 5444. Puede estimar su modelo en el conjunto de prueba y ver el rendimiento. Para evaluar el rendimiento de su modelo, debe utilizar el objeto evaluar. Usted alimenta el modelo con el conjunto de prueba y establece el número de épocas en 1, es decir, los datos irán al modelo solo una vez.

model.evaluate(input_fn=get_input_fn(df_test, 
                                      num_epochs=1,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)
									  
INFO:tensorflow:Calling model_fn.
WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead.
WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-06-02-08:28:22
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from ongoing/train/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Evaluation [100/1000]
INFO:tensorflow:Finished evaluation at 2018-06-02-08:28:23
INFO:tensorflow:Saving dict for global step 1000: accuracy = 0.7615626, accuracy_baseline = 0.76377374, auc = 0.63300294, auc_precision_recall = 0.50891197, average_loss = 47.12155, global_step = 1000, label/mean = 0.23622628, loss = 5993.6406, precision = 0.49401596, prediction/mean = 0.18454961, recall = 0.38637546

{'accuracy': 0.7615626,
 'accuracy_baseline': 0.76377374,
 'auc': 0.63300294,
 'auc_precision_recall': 0.50891197,
 'average_loss': 47.12155,
 'global_step': 1000,
 'label/mean': 0.23622628,
 'loss': 5993.6406,
 'precision': 0.49401596,
 'prediction/mean': 0.18454961,
 'recall': 0.38637546}

TensorFlow devuelve todas las métricas que aprendiste en la parte teórica. Sin sorpresa, la precisión es grande debido a la etiqueta desequilibrada. En realidad, el modelo funciona ligeramente mejor que una suposición aleatoria. Imagine que el modelo predice todos los hogares con ingresos inferiores a 50, entonces el modelo tiene una precisión del 70 por ciento. En un análisis más detallado, se puede ver que la predicción y el recuerdo son bastante bajos.

Paso 4) Mejorar el modelo

Ahora que tiene un modelo de referencia, puede intentar mejorarlo, es decir, aumentar la precisión. En el tutorial anterior, aprendiste cómo mejorar el poder de predicción con un término de interacción. En este tutorial, revisará esta idea agregando un término polinómico a la regresión.

La regresión polinómica es fundamental cuando los datos no son lineales. Hay dos formas de capturar la no linealidad en los datos.

  • Agregar término polinomial
  • Convertir la variable continua en una variable categórica

Término polinómico

En la siguiente imagen, puedes ver qué es una regresión polinómica. Es una ecuación con X variables con diferente potencia. Una regresión polinómica de segundo grado tiene dos variables, X y X al cuadrado. El tercer grado tiene tres variables, X, X.2y X3

Regresión polinomial
¿Qué es la regresión polinómica?

A continuación, construimos una gráfica con dos variables, X e Y. Es obvio que la relación no es lineal. Si agregamos una regresión lineal, podemos ver que el modelo no puede capturar el patrón (imagen de la izquierda).

Ahora, mire la imagen de la izquierda de la siguiente imagen, agregamos cinco términos a la regresión (es decir, y = x + x2+x3+x4+x5. El modelo ahora captura mucho mejor el patrón. Este es el poder de la regresión polinómica.

Regresión polinomial

Volvamos a nuestro ejemplo. La edad no guarda una relación lineal con los ingresos. La edad temprana puede tener un ingreso fijo cercano a cero porque los niños o los jóvenes no trabajan. Luego aumenta en la edad de trabajar y disminuye durante la jubilación. Suele tener forma de U invertida. Una forma de capturar este patrón es agregando una potencia dos a la regresión.

Veamos si aumenta la precisión.

Debe agregar esta nueva característica al conjunto de datos y en la lista de características continuas.

Agrega la nueva variable en el conjunto de datos de entrenamiento y prueba, por lo que es más conveniente escribir una función.

def square_var(df_t, df_te, var_name = 'age'):
    df_t['new'] = df_t[var_name].pow(2) 
    df_te['new'] = df_te[var_name].pow(2) 
    return df_t, df_te

La función tiene 3 argumentos:

  • df_t: define el conjunto de entrenamiento
  • df_te: define el conjunto de prueba
  • var_name = 'edad': define la variable a transformar

Puedes usar el objeto pow(2) para elevar al cuadrado la variable edad. Tenga en cuenta que la nueva variable se denomina "nueva"

Ahora que está escrita la función square_var, puede crear los nuevos conjuntos de datos.

df_train_new, df_test_new = square_var(df_train, df_test, var_name = 'age')

Como puede ver, el nuevo conjunto de datos tiene una característica más.

print(df_train_new.shape, df_test_new.shape)			
(32561, 16) (16281, 16)

La variable cuadrada se llama nueva en el conjunto de datos. Debe agregarlo a la lista de funciones continuas.

CONTI_FEATURES_NEW  = ['age', 'fnlwgt','capital_gain', 'education_num', 'capital_loss', 'hours_week', 'new']
continuous_features_new = [tf.feature_column.numeric_column(k) for k in CONTI_FEATURES_NEW]

Nota: que cambiaste el directorio del Graph. No puedes entrenar diferentes modelos en el mismo directorio. Significa que necesitas cambiar la ruta del argumento model_dir. Si no lo hace, TensorFlow arrojará un error.

model_1 = tf.estimator.LinearClassifier(
    model_dir="ongoing/train1", 
    feature_columns=categorical_features+ continuous_features_new)
INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'ongoing/train1', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': 
<tensorflow.python.training.server_lib.ClusterSpec object at 0x1820f04b70>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}
FEATURES_NEW = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country', 'new']
def get_input_fn(data_set, num_epochs=None, n_batch = 128, shuffle=True):
    return tf.estimator.inputs.pandas_input_fn(
       x=pd.DataFrame({k: data_set[k].values for k in FEATURES_NEW}),
       y = pd.Series(data_set[LABEL].values),
       batch_size=n_batch,   
       num_epochs=num_epochs,
       shuffle=shuffle)

Ahora que el clasificador está diseñado con el nuevo conjunto de datos, puede entrenar y evaluar el modelo.

model_1.train(input_fn=get_input_fn(df_train, 
                                      num_epochs=None,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)
INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into ongoing/train1/model.ckpt.
INFO:tensorflow:loss = 88.722855, step = 1
INFO:tensorflow:global_step/sec: 81.487
INFO:tensorflow:loss = 70077.66, step = 101 (1.228 sec)
INFO:tensorflow:global_step/sec: 111.169
INFO:tensorflow:loss = 49522.082, step = 201 (0.899 sec)
INFO:tensorflow:global_step/sec: 128.91
INFO:tensorflow:loss = 107120.57, step = 301 (0.776 sec)
INFO:tensorflow:global_step/sec: 132.546
INFO:tensorflow:loss = 12814.152, step = 401 (0.755 sec)
INFO:tensorflow:global_step/sec: 162.194
INFO:tensorflow:loss = 19573.898, step = 501 (0.617 sec)
INFO:tensorflow:global_step/sec: 204.852
INFO:tensorflow:loss = 26381.986, step = 601 (0.488 sec)
INFO:tensorflow:global_step/sec: 188.923
INFO:tensorflow:loss = 23417.719, step = 701 (0.529 sec)
INFO:tensorflow:global_step/sec: 192.041
INFO:tensorflow:loss = 23946.049, step = 801 (0.521 sec)
INFO:tensorflow:global_step/sec: 197.025
INFO:tensorflow:loss = 3309.5786, step = 901 (0.507 sec)
INFO:tensorflow:Saving checkpoints for 1000 into ongoing/train1/model.ckpt.
INFO:tensorflow:Loss for final step: 28861.898.

<tensorflow.python.estimator.canned.linear.LinearClassifier at 0x1820f04c88>
model_1.evaluate(input_fn=get_input_fn(df_test_new, 
                                      num_epochs=1,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)
INFO:tensorflow:Calling model_fn.
WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead.
WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-06-02-08:28:37
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from ongoing/train1/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Evaluation [100/1000]
INFO:tensorflow:Finished evaluation at 2018-06-02-08:28:39
INFO:tensorflow:Saving dict for global step 1000: accuracy = 0.7944229, accuracy_baseline = 0.76377374, auc = 0.6093755, auc_precision_recall = 0.54885805, average_loss = 111.0046, global_step = 1000, label/mean = 0.23622628, loss = 14119.265, precision = 0.6682401, prediction/mean = 0.09116262, recall = 0.2576703

{'accuracy': 0.7944229,
 'accuracy_baseline': 0.76377374,
 'auc': 0.6093755,
 'auc_precision_recall': 0.54885805,
 'average_loss': 111.0046,
 'global_step': 1000,
 'label/mean': 0.23622628,
 'loss': 14119.265,
 'precision': 0.6682401,
 'prediction/mean': 0.09116262,
 'recall': 0.2576703}

La variable al cuadrado mejoró la precisión de 0.76 a 0.79. Veamos si puede hacerlo mejor combinando los términos de cuboización e interacción.

Bucketización e interacción

Como vio antes, un clasificador lineal no puede capturar correctamente el patrón edad-ingreso. Esto se debe a que aprende un peso único para cada característica. Para facilitarle las cosas al clasificador, una cosa que puede hacer es agrupar la característica. La agrupación transforma una característica numérica en varias determinadas según el rango en el que se encuentra, y cada una de estas nuevas características indica si la edad de una persona se encuentra dentro de ese rango.

Con estas nuevas características, el modelo lineal puede capturar la relación aprendiendo diferentes pesos para cada segmento.

En TensorFlow, se hace con bucketized_column. Debe agregar el rango de valores en los límites.

age = tf.feature_column.numeric_column('age')
age_buckets = tf.feature_column.bucketized_column(
    age, boundaries=[18, 25, 30, 35, 40, 45, 50, 55, 60, 65])

Ya sabes que la edad no es lineal con los ingresos. Otra forma de mejorar el modelo es mediante la interacción. En palabras de TensorFlow, es cruce de características. El cruce de características es una forma de crear nuevas características que son combinaciones de las existentes, lo que puede ser útil para un clasificador lineal que no puede modelar interacciones entre características.

Puedes desglosar la edad con otra característica como la educación. Es decir, es probable que algunos grupos tengan ingresos altos y otros bajos (pensemos en el estudiante de doctorado).

education_x_occupation = [tf.feature_column.crossed_column(
    ['education', 'occupation'], hash_bucket_size=1000)]
age_buckets_x_education_x_occupation = [tf.feature_column.crossed_column(
    [age_buckets, 'education', 'occupation'], hash_bucket_size=1000)]

Para crear una columna de entidades cruzadas, utilice cross_column con las variables para cruzar entre corchetes. El hash_bucket_size indica las posibilidades máximas de cruce. Para crear interacción entre variables (al menos una variable debe ser categórica), puede usar tf.feature_column.crossed_column. Para usar este objeto, debe agregar entre corchetes la variable para interactuar y un segundo argumento, el tamaño del depósito. El tamaño del depósito es el número máximo de grupos posibles dentro de una variable. Aquí lo configuras en 1000 porque no sabes el número exacto de grupos.

age_buckets debe cuadrarse antes de agregarlo a las columnas de funciones. También agrega las nuevas características a las columnas de características y prepara el estimador.

base_columns = [
    age_buckets,
]

model_imp = tf.estimator.LinearClassifier(
    model_dir="ongoing/train3", 
    feature_columns=categorical_features+base_columns+education_x_occupation+age_buckets_x_education_x_occupation)

Salida

INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'ongoing/train3', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1823021be0>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}
FEATURES_imp = ['age','workclass', 'education', 'education_num', 'marital',
                'occupation', 'relationship', 'race', 'sex', 'native_country', 'new']

def get_input_fn(data_set, num_epochs=None, n_batch = 128, shuffle=True):
    return tf.estimator.inputs.pandas_input_fn(
       x=pd.DataFrame({k: data_set[k].values for k in FEATURES_imp}),
       y = pd.Series(data_set[LABEL].values),
       batch_size=n_batch,   
       num_epochs=num_epochs,
       shuffle=shuffle)

Está listo para estimar el nuevo modelo y ver si mejora la precisión.

model_imp.train(input_fn=get_input_fn(df_train_new, 
                                      num_epochs=None,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)
									  
INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into ongoing/train3/model.ckpt.
INFO:tensorflow:loss = 88.722855, step = 1
INFO:tensorflow:global_step/sec: 94.969
INFO:tensorflow:loss = 50.334488, step = 101 (1.054 sec)
INFO:tensorflow:global_step/sec: 242.342
INFO:tensorflow:loss = 56.153225, step = 201 (0.414 sec)
INFO:tensorflow:global_step/sec: 213.686
INFO:tensorflow:loss = 45.792007, step = 301 (0.470 sec)
INFO:tensorflow:global_step/sec: 174.084
INFO:tensorflow:loss = 37.485672, step = 401 (0.572 sec)
INFO:tensorflow:global_step/sec: 191.78
INFO:tensorflow:loss = 56.48449, step = 501 (0.524 sec)
INFO:tensorflow:global_step/sec: 163.436
INFO:tensorflow:loss = 32.528934, step = 601 (0.612 sec)
INFO:tensorflow:global_step/sec: 164.347
INFO:tensorflow:loss = 37.438057, step = 701 (0.607 sec)
INFO:tensorflow:global_step/sec: 154.274
INFO:tensorflow:loss = 61.1075, step = 801 (0.647 sec)
INFO:tensorflow:global_step/sec: 189.14
INFO:tensorflow:loss = 44.69645, step = 901 (0.531 sec)
INFO:tensorflow:Saving checkpoints for 1000 into ongoing/train3/model.ckpt.
INFO:tensorflow:Loss for final step: 44.18133.

<tensorflow.python.estimator.canned.linear.LinearClassifier at 0x1823021cf8>
model_imp.evaluate(input_fn=get_input_fn(df_test_new, 
                                      num_epochs=1,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)
									  
INFO:tensorflow:Calling model_fn.
WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead.
WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-06-02-08:28:52
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from ongoing/train3/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Evaluation [100/1000]
INFO:tensorflow:Finished evaluation at 2018-06-02-08:28:54
INFO:tensorflow:Saving dict for global step 1000: accuracy = 0.8358209, accuracy_baseline = 0.76377374, auc = 0.88401634, auc_precision_recall = 0.69599575, average_loss = 0.35122654, global_step = 1000, label/mean = 0.23622628, loss = 44.67437, precision = 0.68986726, prediction/mean = 0.23320661, recall = 0.55408216


{'accuracy': 0.8358209,
 'accuracy_baseline': 0.76377374,
 'auc': 0.88401634,
 'auc_precision_recall': 0.69599575,
 'average_loss': 0.35122654,
 'global_step': 1000,
 'label/mean': 0.23622628,
 'loss': 44.67437,
 'precision': 0.68986726,
 'prediction/mean': 0.23320661,
 'recall': 0.55408216}

El nuevo nivel de precisión es del 83.58 por ciento. Es un cuatro por ciento más alto que el modelo anterior.

Finalmente, puede agregar un término de regularización para evitar el sobreajuste.

Paso 5) Hiperparámetro: Lazo y Ridge

Su modelo puede sufrir sobreajuste or desajuste.

  • Sobreajuste: el modelo no puede generalizar la predicción a nuevos datos.
  • Desajuste: el modelo no puede capturar el patrón de los datos. es decir, regresión lineal cuando los datos no son lineales

Cuando un modelo tiene muchos parámetros y una cantidad relativamente baja de datos, genera predicciones deficientes. Imagínese, un grupo sólo tiene tres observaciones; el modelo calculará un peso para este grupo. El peso se utiliza para hacer una predicción; Si las observaciones del conjunto de prueba para este grupo en particular son completamente diferentes del conjunto de entrenamiento, entonces el modelo hará una predicción incorrecta. Durante la evaluación con el conjunto de entrenamiento, la precisión es buena, pero no buena con el conjunto de prueba porque los pesos calculados no son los verdaderos para generalizar el patrón. En este caso, no hace una predicción razonable sobre datos invisibles.

Para evitar el sobreajuste, la regularización le brinda la posibilidad de controlar dicha complejidad y hacerla más generalizable. Existen dos técnicas de regularización:

  • L1: Lazo
  • L2: cresta

En TensorFlow, puedes agregar estos dos hiperparámetros en el optimizador. Por ejemplo, cuanto mayor es el hiperparámetro L2, el peso tiende a ser muy bajo y cercano a cero. La línea ajustada será muy plana, mientras que un L2 cercano a cero implica que los pesos están cerca de la regresión lineal regular.

Puede probar usted mismo los diferentes valores de los hiperparámetros y ver si puede aumentar el nivel de precisión.

Nota: que si cambia el hiperparámetro, debe eliminar la carpeta progress/train4, de lo contrario, el modelo comenzará con el modelo entrenado previamente.

A ver cómo va la precisión con el hype.

model_regu = tf.estimator.LinearClassifier(
    model_dir="ongoing/train4", feature_columns=categorical_features+base_columns+education_x_occupation+age_buckets_x_education_x_occupation,
    optimizer=tf.train.FtrlOptimizer(
        learning_rate=0.1,
        l1_regularization_strength=0.9,
        l2_regularization_strength=5))

SALIDA

INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'ongoing/train4', '_tf_random_seed': None, '_save_summary_steps': 100, '_save_checkpoints_steps': None, '_save_checkpoints_secs': 600, '_session_config': None, '_keep_checkpoint_max': 5, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_train_distribute': None, '_service': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x1820d9c128>, '_task_type': 'worker', '_task_id': 0, '_global_id_in_cluster': 0, '_master': '', '_evaluation_master': '', '_is_chief': True, '_num_ps_replicas': 0, '_num_worker_replicas': 1}
model_regu.train(input_fn=get_input_fn(df_train_new, 
                                      num_epochs=None,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)

SALIDA

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 1 into ongoing/train4/model.ckpt.
INFO:tensorflow:loss = 88.722855, step = 1
INFO:tensorflow:global_step/sec: 77.4165
INFO:tensorflow:loss = 50.38778, step = 101 (1.294 sec)
INFO:tensorflow:global_step/sec: 187.889
INFO:tensorflow:loss = 55.38014, step = 201 (0.535 sec)
INFO:tensorflow:global_step/sec: 201.895
INFO:tensorflow:loss = 46.806694, step = 301 (0.491 sec)
INFO:tensorflow:global_step/sec: 217.992
INFO:tensorflow:loss = 38.68271, step = 401 (0.460 sec)
INFO:tensorflow:global_step/sec: 193.676
INFO:tensorflow:loss = 56.99398, step = 501 (0.516 sec)
INFO:tensorflow:global_step/sec: 202.195
INFO:tensorflow:loss = 33.263622, step = 601 (0.497 sec)
INFO:tensorflow:global_step/sec: 216.756
INFO:tensorflow:loss = 37.7902, step = 701 (0.459 sec)
INFO:tensorflow:global_step/sec: 240.215
INFO:tensorflow:loss = 61.732605, step = 801 (0.416 sec)
INFO:tensorflow:global_step/sec: 220.336
INFO:tensorflow:loss = 46.938225, step = 901 (0.456 sec)
INFO:tensorflow:Saving checkpoints for 1000 into ongoing/train4/model.ckpt.
INFO:tensorflow:Loss for final step: 43.4942.


<tensorflow.python.estimator.canned.linear.LinearClassifier at 0x181ff39e48>
model_regu.evaluate(input_fn=get_input_fn(df_test_new, 
                                      num_epochs=1,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)

Salida

INFO:tensorflow:Calling model_fn.
WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead.
WARNING:tensorflow:Trapezoidal rule is known to produce incorrect PR-AUCs; please switch to "careful_interpolation" instead.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-06-02-08:29:07
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from ongoing/train4/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Evaluation [100/1000]
INFO:tensorflow:Finished evaluation at 2018-06-02-08:29:09
INFO:tensorflow:Saving dict for global step 1000: accuracy = 0.83833915, accuracy_baseline = 0.76377374, auc = 0.8869794, auc_precision_recall = 0.7014905, average_loss = 0.34691378, global_step = 1000, label/mean = 0.23622628, loss = 44.12581, precision = 0.69720596, prediction/mean = 0.23662092, recall = 0.5579823





{'accuracy': 0.83833915,
 'accuracy_baseline': 0.76377374,
 'auc': 0.8869794,
 'auc_precision_recall': 0.7014905,
 'average_loss': 0.34691378,
 'global_step': 1000,
 'label/mean': 0.23622628,
 'loss': 44.12581,
 'precision': 0.69720596,
 'prediction/mean': 0.23662092,
 'recall': 0.5579823}

Con este hiperparámetro, aumenta ligeramente las métricas de precisión. En el siguiente tutorial, aprenderá cómo mejorar un clasificador lineal utilizando un método del núcleo.

Resumen

Para entrenar un modelo, necesitas:

  • Definir las características: Variables independientes: X
  • Defina la etiqueta: Variable dependiente: y
  • Construir un tren/conjunto de prueba
  • Definir el peso inicial
  • Definir la función de pérdida: MSE
  • Optimizar el modelo: descenso de gradiente
  • Definir:
    • Tasa de aprendizaje
    • Número de época
    • Tamaño del lote
    • numero de clase

En este tutorial, aprendió a utilizar la API de alto nivel para un clasificador de regresión lineal. Necesitas definir:

  1. Columnas de características. Si es continuo: tf.feature_column.numeric_column(). Puede completar una lista con comprensión de lista de Python
  2. El estimador: tf.estimator.LinearClassifier(feature_columns, model_dir, n_classes = 2)
  3. Una función para importar los datos, el tamaño del lote y la época: input_fn()

Después de eso, estás listo para entrenar, evaluar y hacer una predicción con train(), evalua() y predict().

Para mejorar el rendimiento del modelo, puede:

  • Usar regresión polinómica
  • Término de interacción: tf.feature_column.crossed_column
  • Agregar parámetro de regularización