Classificação binária do TensorFlow: exemplo de classificador linear
⚡ Resumo Inteligente
Classificadores lineares atribuem cada observação a uma classe com base na soma ponderada de suas características. Este tutorial constrói um classificador binário em TensorFlow no conjunto de dados do censo e aumenta a precisão de 0.76 para 0.84.
Os dois mais comuns aprendizagem supervisionada as tarefas são regressão linear e classificador linear. A regressão linear prevê um valor enquanto o classificador linear prevê uma classe. Este tutorial é focado em Classificadores Lineares.
O que é classificador linear?
A Classificador Linear em Machine Learning é um método para encontrar a classe de um objeto com base em suas características para classificação estatística. Toma decisões de classificação com base no valor de uma combinação linear de características de um objeto. O classificador linear é usado em problemas práticos como classificação de documentos e problemas com muitas variáveis.
Os problemas de classificação representam cerca de 80% da tarefa de aprendizado de máquina. A classificação visa prever a probabilidade de cada classe dado um conjunto de entradas. O rótulo (ou seja, a variável dependente) é um valor discreto, denominado classe.
- Se o rótulo tiver apenas duas classes, o algoritmo de aprendizagem é um Classificador Binário.
- O classificador multiclasse aborda rótulos com mais de duas classes.
Por exemplo, um problema típico de classificação binária é prever a probabilidade de um cliente fazer uma segunda compra. Prever o tipo de animal exibido em uma imagem é um problema de classificação multiclasse, uma vez que existem mais de duas variedades de animais.
A parte teórica deste tutorial coloca o foco principal na classe binária. Você aprenderá mais sobre a função de saída multiclasse em um tutorial futuro.
Com a definição estabelecida, o próximo passo é ver como o algoritmo transforma as características brutas em uma decisão de classe.
Como funciona o classificador binário?
Você aprendeu no tutorial anterior que uma função é composta por dois tipos de variáveis, uma variável dependente e um conjunto de recursos (variáveis independentes). Na regressão linear, uma variável dependente é um número real sem intervalo. O objetivo principal é prever seu valor minimizando o erro quadrático médio.
Para TensorFlow Em um classificador binário, o rótulo pode ter dois valores inteiros possíveis. Na maioria dos casos, é [0,1] ou [1,2]. Por exemplo, o objetivo é prever se um cliente comprará um produto ou não. O rótulo é definido da seguinte forma:
- Y = 1 (o cliente comprou o produto)
- Y = 0 (o cliente não compra o produto)
O modelo utiliza as características X para classificar cada cliente na classe mais provável a que ele pertence, ou seja, potencial comprador ou não.
A probabilidade de sucesso é calculada com regressão logística. O algoritmo calculará uma probabilidade com base no recurso X e prevê um sucesso quando essa probabilidade estiver acima de 50 por cento. Mais formalmente, a probabilidade é calculada conforme mostrado no exemplo de classificação binária do TensorFlow abaixo:
onde 0 é o conjunto de pesos, os recursos eb o viés.
A função pode ser decomposta em duas partes:
- O modelo linear
- A função logística
Modelo linear
Você já está familiarizado com a forma como os pesos são calculados. Os pesos são calculados usando um produto escalar: Y é uma função linear de todos os recursos xi. Se o modelo não possuir características, a previsão é igual ao viés, b.
Os pesos indicam a direção da correlação entre os recursos xi e o rótulo y. Uma correlação positiva aumenta a probabilidade da classe positiva, enquanto uma correlação negativa aproxima a probabilidade de 0 (ou seja, classe negativa).
O modelo linear retorna apenas números reais, o que é inconsistente com a medida de probabilidade do intervalo [0,1]. A função logística é necessária para converter a saída do modelo linear em uma probabilidade,
Função logística
A função logística, ou função sigmóide, tem formato de S e a saída desta função está sempre entre 0 e 1.
A fórmula abaixo descreve a transformação, e o gráfico que se segue mostra a curva resultante achatando-se em direção a 0 à esquerda e em direção a 1 à direita.

É fácil substituir a saída da regressão linear na função sigmóide. Isso resulta em um novo número com probabilidade entre 0 e 1.
O classificador pode transformar a probabilidade em uma classe
- Valores entre 0 e 0.49 passam a ser classe 0
- Valores entre 0.5 e 1 passam a ser classe 1
Uma vez que o modelo produza classes, você precisa de uma maneira de avaliar se essas classes são boas.
Como medir o desempenho do classificador linear?
Precisão
O desempenho geral de um classificador é medido com a métrica de precisão. A precisão coleta todos os valores corretos divididos pelo número total de observações. Por exemplo, um valor de precisão de 80% significa que o modelo está correto em 80% dos casos.
Você pode notar uma deficiência nessa métrica, especialmente para a classe de desequilíbrio. Um conjunto de dados de desequilíbrio ocorre quando o número de observações por grupo não é igual. Digamos; você tenta classificar um evento raro com uma função logística. Imagine que o classificador tente estimar a morte de um paciente após uma doença. Nos dados, 5% dos pacientes falecem. Você pode treinar um classificador para prever o número de mortes e usar a métrica de precisão para avaliar o desempenho. Se o classificador prever 0 morte para todo o conjunto de dados, estará correto em 95% dos casos.
Matriz de confusão
A melhor maneira de avaliar o desempenho de um classificador é observar a matriz de confusão.
O matriz de confusão visualiza a precisão de um classificador comparando as classes reais e previstas, conforme mostrado no exemplo do Classificador Linear acima. A matriz de confusão binária é composta por quadrados:
- TP: Verdadeiro Positivo: Valores previstos corretamente como positivos reais
- FP: Os valores previstos previram incorretamente um positivo real. ou seja, valores negativos previstos como positivos
- FN: Falso Negativo: Valores positivos previstos como negativos
- TN: Verdadeiro Negativo: Valores previstos corretamente como negativos reais
A partir da matriz de confusão, é fácil comparar a classe real e a classe prevista.
Precisão e Sensibilidade
A matriz de confusão fornece uma boa visão do verdadeiro positivo e do falso positivo. Em alguns casos, é preferível ter uma métrica mais concisa.
Precisão
A métrica de precisão mostra a precisão da classe positiva. Ele mede a probabilidade de a previsão da classe positiva estar correta.
A pontuação máxima é 1 quando o classificador classifica perfeitamente todos os valores positivos. A precisão por si só não é muito útil porque ignora a classe negativa. A métrica geralmente é combinada com a métrica Recall. A recuperação também é chamada de sensibilidade ou taxa de verdadeiro positivo.
à Taxa de juros
A sensibilidade calcula a proporção de classes positivas detectadas corretamente. Essa métrica mostra o quão bom o modelo é para reconhecer uma classe positiva.
A teoria já está estabelecida, então o restante deste passo a passo a aplica de ponta a ponta no código.
Classificador Linear com TensorFlow
Para este tutorial, usaremos o conjunto de dados do censo. O objetivo é usar as variáveis do conjunto de dados do censo para prever o nível de renda. Observe que a renda é uma variável binária
- com valor 1 se a renda > 50k
- 0 se renda < 50k.
Esta variável é o seu rótulo
Este conjunto de dados inclui oito variáveis categóricas:
- local de trabalho
- educação
- marital
- ocupação
- relacionamento
- raça
- sexo
- país nativo
além disso, seis variáveis contínuas:
- idade
- fnlwgt
- número_educação
- Ganho de capital
- perda_capital
- horas_semana
Por meio deste exemplo de classificação do TensorFlow, você entenderá como treinar classificadores lineares do TensorFlow com o estimador do TensorFlow e como melhorar a métrica de precisão.
Nota de versão: O código abaixo utiliza a API Estimator do TensorFlow 1.x. tf-estimator O pacote foi lançado em sua versão final com o TensorFlow 2.15 e não está disponível no TensorFlow 2.16 ou posterior. Portanto, execute esses trechos de código no TensorFlow 1.x ou utilize a versão oficial. guia de migração de estimador pré-definidoOs conceitos, a engenharia de funcionalidades e as métricas permanecem os mesmos.
Procederemos da seguinte forma:
- Etapa 1) Importe os dados
- Etapa 2) Conversão de dados
- Etapa 3) Treine o classificador
- Etapa 4) Melhorar o modelo
- Etapa 5) Hiperparâmetro: Lasso e Ridge
Etapa 1) Importe os dados
Primeiro você importa as bibliotecas usadas durante o tutorial.
import tensorflow as tf import pandas as pd
A seguir, você importa os dados do arquivo UCI e define os nomes das colunas. Você usará COLUMNS para nomear as colunas em um quadro de dados do pandas.
Observe que você treinará o classificador usando um dataframe do 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"
Os dados armazenados online já estão divididos entre um conjunto de treinamento e um conjunto de teste.
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)
O conjunto de trem contém 32,561 observações e o conjunto de teste 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
O TensorFlow requer um valor booleano para treinar o classificador. Você precisa converter os valores de string para inteiro. O rótulo é armazenado como um objeto, porém, você precisa convertê-lo em um valor numérico. O código abaixo cria um dicionário com os valores a serem convertidos e itera sobre o item da coluna. Observe que você realiza essa operação duas vezes, uma para o conjunto de treinamento e outra para o conjunto de teste.
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]
Nos dados de treinamento, há 24,720 rendimentos inferiores a 50 mil e 7841 superiores. A proporção é quase a mesma no conjunto de teste, portanto, aproximadamente 76% de ambas as divisões pertencem à classe negativa.
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
Etapa 2) Conversão de dados
Algumas etapas são necessárias antes de treinar um classificador linear com o TensorFlow. Você precisa preparar os recursos que serão incluídos no modelo. Na regressão de referência, você usará os dados originais sem aplicar nenhuma transformação, exatamente como um modelo. scikit-learn O pipeline começaria a partir de colunas brutas.
O estimador precisa ter uma lista de recursos para treinar o modelo. Conseqüentemente, os dados da coluna precisam ser convertidos em um tensor.
Uma boa prática é definir duas listas de recursos com base em seu tipo e depois passá-las em feature_columns do estimador.
Você começará convertendo recursos contínuos e, em seguida, definirá um intervalo com os dados categóricos.
Os recursos do conjunto de dados têm dois formatos:
- Número inteiro
- objeto
Cada recurso é listado nas próximas duas variáveis de acordo com seus 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']
O feature_column é equipado com um objeto numeric_column para auxiliar na transformação das variáveis contínuas em tensor. No código abaixo, você converte todas as variáveis de CONTI_FEATURES em um tensor com valor numérico. Isso é obrigatório para construir o modelo. Todas as variáveis independentes precisam ser convertidas no tipo adequado de tensor.
A seguir, apresentamos um código para que você possa ver o que está acontecendo por trás de `feature_column.numeric_column`. Imprimiremos o valor convertido para `age`. Isso é apenas para fins explicativos; portanto, não é necessário entender o código. Python código. Você pode consultar a documentação oficial para entender os 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.]]
Os valores são exatamente iguais aos de df_train
continuous_features = [tf.feature_column.numeric_column(k) for k in CONTI_FEATURES]
De acordo com a documentação do TensorFlow, existem diferentes maneiras de converter dados categóricos. Se a lista de vocabulário de um recurso for conhecida e não possuir muitos valores, é possível criar a coluna categórica com categorical_column_with_vocabulary_list. Ele atribuirá um ID a todas as listas de vocabulário exclusivas.
Por exemplo, se um status de variável tiver três valores distintos:
- Marido
- Esposa
- Individual
Então três ID serão atribuídos. Por exemplo, o Marido terá o ID 1, a Esposa o ID 2 e assim por diante.
Para fins ilustrativos, você pode usar este código para converter uma variável de objeto em uma coluna categórica no TensorFlow.
A variável `sex` pode ter apenas dois valores: masculino ou feminino. Ao converter a variável `sex`, o TensorFlow criará duas novas colunas, uma para masculino e outra para feminino. Se o valor de `sex` for igual a masculino, a nova coluna `male` terá o valor 1 e a coluna `female` terá o valor 0. Este exemplo é mostrado na tabela abaixo:
| linhas | sexo | depois da transformação | masculina | feminina |
|---|---|---|---|---|
| 1 | masculina | => | 1 | 0 |
| 2 | masculina | => | 1 | 0 |
| 3 | feminina | => | 0 | 1 |
No fluxo 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'])
Abaixo, adicionamos Python código para imprimir a codificação. Novamente, você não precisa entender o código, o objetivo é ver a transformação
No entanto, uma maneira mais rápida de transformar os dados é usar o método `categorical_column_with_hash_bucket`. Alterar variáveis de string em uma matriz esparsa será útil. Uma matriz esparsa é uma matriz composta principalmente por zeros. O método cuida de tudo. Você só precisa especificar o número de buckets e a coluna chave. O número de buckets é a quantidade máxima de grupos que o TensorFlow pode criar. A coluna chave é simplesmente o nome da coluna a ser convertida.
No código abaixo, você cria um loop sobre todos os recursos categóricos.
categorical_features = [tf.feature_column.categorical_column_with_hash_bucket(k, hash_bucket_size=1000) for k in CATE_FEATURES]
Etapa 3) Treine o Classificador
Atualmente, o TensorFlow fornece um estimador para regressão linear e classificação linear.
- Regressão linear: LinearRegressor
- Classificação linear: LinearClassifier
A sintaxe do classificador linear é a mesma do tutorial em regressão linear exceto por um argumento, n_class. Você precisa definir a coluna de recursos, o diretório do modelo e comparar com o regressor linear; você tem que definir o número da aula. Para uma regressão logit, o número de turmas é igual a 2.
O modelo calculará os pesos das colunas contidas em Continuous_features e categorical_features.
model = tf.estimator.LinearClassifier(
n_classes = 2,
model_dir="ongoing/train",
feature_columns=categorical_features+ continuous_features)
saída
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}
Agora que o classificador está definido, você pode criar a função de entrada. O método é o mesmo do tutorial do regressor linear. Aqui, você usa um tamanho de lote de 128 e embaralha os dados.
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)
Você cria uma função com os argumentos exigidos pelo estimador linear, ou seja, número de épocas, número de lotes e embaralha o conjunto de dados ou nota. Já que você usa o Pandas método para passar os dados para o modelo, você precisa definir as variáveis X como um quadro de dados do pandas. Observe que você percorre todos os dados armazenados em FEATURES.
Vamos treinar o modelo com o objeto model.train. Você usa a função definida anteriormente para alimentar o modelo com os valores apropriados. Observe que você definiu o tamanho do lote como 128 e o número de épocas como Nenhum. O modelo será treinado em mil etapas.
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>
Observe que a perda diminuiu posteriormente durante as últimas 100 etapas, ou seja, de 901 para 1000.
A perda final após mil iterações é 5444. Você pode estimar seu modelo no conjunto de testes e ver o desempenho. Para avaliar o desempenho do seu modelo, você precisa usar o objetoavaliar. Você alimenta o modelo com o conjunto de testes e define o número de épocas como 1, ou seja, os dados irão para o modelo apenas uma 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}
O TensorFlow retorna todas as métricas que você aprendeu na parte teórica. Sem surpresa, a precisão é grande devido ao rótulo desequilibrado. Na verdade, o modelo tem um desempenho ligeiramente melhor do que uma estimativa aleatória. Imagine que o modelo preveja todas as famílias com renda inferior a 50 mil, então o modelo tem uma precisão de 70%. Em uma análise mais detalhada, você pode ver que a previsão e o recall são bastante baixos.
Etapa 4) Melhorar o modelo
Agora que você tem um modelo de benchmark, pode tentar melhorá-lo, ou seja, aumentar a precisão. No tutorial anterior, você aprendeu como melhorar o poder de predição com um termo de interação. Neste tutorial, você revisitará essa ideia adicionando um termo polinomial à regressão.
A regressão polinomial é fundamental quando há não linearidade nos dados. Existem duas maneiras de capturar a não linearidade nos dados.
- Adicionar termo polinomial
- Divida a variável contínua em uma variável categórica
Termo polinomial
Na imagem abaixo você pode ver o que é uma regressão polinomial. É uma equação com variáveis X com potências diferentes. Uma regressão polinomial de segundo grau tem duas variáveis, X e X ao quadrado. Terceiro grau tem três variáveis, X, X2e X3
O gráfico acima mostra uma curva de segundo grau em função da equação subjacente. Abaixo, construímos um gráfico com duas variáveis, X e Y. É evidente que a relação não é linear. Se adicionarmos uma regressão linear, podemos ver que o modelo não consegue capturar o padrão (imagem à esquerda).
Agora, olhe para a imagem à esquerda da imagem abaixo, adicionamos cinco termos à regressão (ou seja, y=x+x2+x3+x4+x5. O modelo agora captura muito melhor o padrão. Este é o poder da regressão polinomial.
Voltemos ao nosso exemplo. A idade não está numa relação linear com a renda. A idade precoce pode ter um rendimento fixo próximo de zero porque as crianças ou os jovens não trabalham. Depois aumenta na idade activa e diminui durante a reforma. Normalmente é uma forma de U invertido. Uma maneira de capturar esse padrão é adicionar uma potência dois à regressão.
Vamos ver se isso aumenta a precisão.
Você precisa adicionar este novo recurso ao conjunto de dados e na lista de recursos contínuos.
Você adiciona a nova variável no conjunto de dados de treinamento e teste, por isso é mais conveniente escrever uma função.
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
A função tem 3 argumentos:
- df_t: define o conjunto de treinamento
- df_te: define o conjunto de testes
- var_name = 'age': Defina a variável a ser transformada
Você pode usar o objeto pow(2) para elevar ao quadrado a variável idade. Observe que a nova variável é chamada de 'new'
Agora que a função square_var foi escrita, você pode criar os novos conjuntos de dados.
df_train_new, df_test_new = square_var(df_train, df_test, var_name = 'age')
Como você pode ver, o novo conjunto de dados possui mais um recurso.
print(df_train_new.shape, df_test_new.shape)
(32561, 16) (16281, 16)
A variável quadrada é chamada de nova no conjunto de dados. Você precisa adicioná-lo à lista de recursos contínuos.
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]
Observação que você alterou o diretório do Gráfico. Você não pode treinar modelos diferentes no mesmo diretório. Isso significa que você precisa alterar o caminho do argumento model_dir. Caso contrário, o TensorFlow gerará um erro.
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)
Agora que o classificador foi projetado com o novo conjunto de dados, você pode treinar e avaliar o 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}
A variável quadrada melhorou a precisão de 0.76 para 0.79. Vamos ver se você consegue fazer melhor combinando bucketização e termo de interação.
Bucketização e interação
Como você viu antes, um classificador linear é incapaz de capturar corretamente o padrão idade-renda. Isso ocorre porque ele aprende um único peso para cada recurso. Para tornar mais fácil para o classificador, uma coisa que você pode fazer é agrupar o recurso. O agrupamento transforma um recurso numérico em vários determinados com base no intervalo em que ele se enquadra, e cada um desses novos recursos indica se a idade de uma pessoa está dentro desse intervalo.
Com esses novos recursos, o modelo linear pode capturar o relacionamento aprendendo pesos diferentes para cada intervalo.
No TensorFlow, isso é feito com bucketized_column. Você precisa adicionar o intervalo de valores nos limites.
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])
Você já sabe que a idade não é linear com a renda. Outra forma de melhorar o modelo é por meio da interação. Nas palavras do TensorFlow, é cruzamento de recursos. O cruzamento de recursos é uma forma de criar novos recursos que são combinações de recursos existentes, o que pode ser útil para um classificador linear que não consegue modelar interações entre recursos.
Você pode dividir a idade com outro recurso, como a educação. Ou seja, alguns grupos provavelmente terão renda alta e outros baixa (pense no estudante de doutorado).
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 criar uma coluna de características cruzadas, você usa cross_column com as variáveis a serem cruzadas entre colchetes. O hash_bucket_size indica as possibilidades máximas de cruzamento. Para criar interação entre variáveis (pelo menos uma variável precisa ser categórica), você pode usar tf.feature_column.crossed_column. Para usar este objeto, você precisa adicionar entre colchetes a variável para interagir e um segundo argumento, o tamanho do balde. O tamanho do bucket é o número máximo de grupos possível dentro de uma variável. Aqui você define como 1000 porque não sabe o número exato de grupos
age_buckets precisa ser elevado ao quadrado antes de adicioná-lo às colunas de recursos. Você também adiciona os novos recursos às colunas de recursos e prepara o 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)
saída
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)
Você está pronto para estimar o novo modelo e ver se ele melhora a precisão.
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}
O novo nível de precisão é de 83.58%. É quatro por cento maior que o modelo anterior.
Finalmente, você pode adicionar um termo de regularização para evitar overfitting.
Etapa 5) Hiperparâmetro: Lasso e Ridge
Seu modelo pode sofrer sobreajuste or insuficiente.
- Overfitting: o modelo é incapaz de generalizar a previsão para novos dados
- Underfitting: O modelo não consegue capturar o padrão dos dados. ou seja, regressão linear quando os dados são não lineares
Quando um modelo tem muitos parâmetros e uma quantidade relativamente baixa de dados, isso leva a previsões ruins. Imagine, um grupo tem apenas três observações; o modelo calculará um peso para este grupo. O peso é usado para fazer uma previsão; se as observações do conjunto de teste para este grupo específico forem totalmente diferentes do conjunto de treinamento, então o modelo fará uma previsão errada. Durante a avaliação com o conjunto de treinamento, a precisão é boa, mas não boa com o conjunto de teste porque os pesos calculados não são os verdadeiros para generalizar o padrão. Neste caso, não faz uma previsão razoável sobre dados não vistos.
Para evitar overfitting, a regularização oferece a possibilidade de controlar essa complexidade e torná-la mais generalizável. Existem duas técnicas de regularização:
- L1: Laço
- L2: Cume
No TensorFlow, você pode adicionar esses dois hiperparâmetros no otimizador. Por exemplo, quanto maior o hiperparâmetro L2, o peso tende a ser muito baixo e próximo de zero. A linha ajustada será muito plana, enquanto um L2 próximo de zero implica que os pesos estão próximos da regressão linear regular.
Você pode tentar sozinho os diferentes valores dos hiperparâmetros e ver se consegue aumentar o nível de precisão.
Observação que se você alterar o hiperparâmetro, será necessário excluir a pasta em andamento/train4 caso contrário o modelo iniciará com o modelo previamente treinado.
Vamos ver como está a precisão com o 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))
saída
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)
saída
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)
saída
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}
Com esse hiperparâmetro, você aumenta ligeiramente as métricas de precisão. A tabela abaixo reúne todas as métricas relatadas pelas quatro chamadas de avaliação neste tutorial.
| Modelo | Conjunto de características | Precisão | AUC | Precisão | Recordar |
|---|---|---|---|---|---|
| modelo | Linha de base contínua + categórica | 0.7615626 | 0.63300294 | 0.49401596 | 0.38637546 |
| modelo_1 | Idade basal mais o quadrado | 0.7944229 | 0.6093755 | 0.6682401 | 0.2576703 |
| modelo_impac | Idade categorizada em grupos mais colunas cruzadas | 0.8358209 | 0.88401634 | 0.68986726 | 0.55408216 |
| modelo_regu | Colunas cruzadas mais L1 e L2 | 0.83833915 | 0.8869794 | 0.69720596 | 0.5579823 |
Note que a precisão básica de um modelo que sempre prevê a classe majoritária é de 0.76377374, portanto, apenas os dois últimos modelos superam uma estimativa trivial por uma margem útil.
No próximo tutorial, você aprenderá como aprimorar um classificador linear usando um método kernel.




