Regressão linear do TensorFlow com faceta e termo de interação

⚡ Resumo Inteligente

A regressão linear aplicada aos dados imobiliários de Boston apresenta melhorias quando os termos de interação corretos são identificados previamente. Google O Facets expõe essas relações visualmente, e duas características cruzadas reduzem a perda do teste TensorFlow de 1650 para 1515.

  • 🔘 Os dados em primeiro lugar: Compreender as distribuições e os valores discrepantes precede qualquer modelo, pois um modelo apenas generaliza um padrão que você já identificou.
  • ☑️ Visão geral das facetas: As estatísticas por característica expõem valores ausentes, colunas com excesso de zeros e desvios na distribuição entre os conjuntos de treino e teste em uma única tabela.
  • Análise Detalhada das Facetas: A divisão em gráficos por X e Y transforma relações de três vias em um gráfico 2D legível, colorido por quartil de preço.
  • 🧪 Leitura correlacionada: O mapa de calor e a grade de pares indicam INDUS com NOX e DIS com ambos como possíveis interações.
  • 🛠️ Estandardização: O preprocessing.scale centraliza as doze colunas contínuas antes que o estimador as veja, deixando CHAS e PRICE inalteradas.
  • 📈 Ganho medido: A adição de INDUS_NOS e INDUS_NOS_DIS eleva a perda média de 86.89361 para 79.78876 no desdobramento de teste.

Regressão Linear do TensorFlow com Facetas e Termos de Interação

Regressão Linear com TensorFlow

Neste tutorial, você aprenderá como verificar os dados e prepará-los para criar uma tarefa simples de regressão linear.

Este tutorial está dividido em duas partes:

  • Procure interação
  • Teste o modelo

De acordo com o relatório tutorial anterior, você usou o conjunto de dados de Boston para estimar o preço médio de uma casa. O conjunto de dados de Boston tem um tamanho pequeno, com apenas 506 observações. Este conjunto de dados é considerado uma referência para testar novos algoritmos de regressão linear.

O conjunto de dados é composto por:

Variável Descrição
zn A proporção de terrenos residenciais zoneados para lotes com mais de 25,000 pés quadrados.
indus A proporção de acres comerciais não varejistas por cidade.
nox concentração de óxidos nítricos
rm número médio de quartos por habitação
idade a proporção de unidades ocupadas pelos proprietários construídas antes de 1940
dis distâncias ponderadas para cinco centros de emprego de Boston
imposto taxa de imposto sobre a propriedade de valor total por dólares 10,000
ptratio a proporção aluno-professor por cidade
medv O valor médio das casas ocupadas pelos proprietários em milhares de dólares
criminoso taxa de criminalidade per capita por cidade
chas Variável fictícia Charles River (1 se limita o rio; 0 caso contrário)
B a proporção de negros pela cidade

Neste tutorial, estimaremos o preço mediano usando um regressor linear, mas o foco está em um processo específico de aprendizado de máquina: "preparação de dados."

Um modelo generaliza o padrão nos dados. Para capturar esse padrão, você precisa primeiro encontrá-lo. Uma boa prática é realizar uma análise de dados antes de executar qualquer algoritmo de aprendizado de máquina.

Escolher os recursos certos faz toda a diferença no sucesso do seu modelo. Imagine que você tenta estimar o salário de um povo, se não incluir o gênero como covariável, você acaba com uma estimativa ruim.

Outra forma de melhorar o modelo é observar a correlação entre a variável independente. Voltando ao exemplo, você pode pensar na educação como um excelente candidato para prever o salário, mas também a ocupação. É justo dizer que a profissão depende do nível de escolaridade, nomeadamente o ensino superior conduz frequentemente a uma melhor profissão. Se generalizarmos esta ideia, podemos dizer que a correlação entre a variável dependente e uma variável explicativa pode ser ampliada por mais uma variável explicativa.

Para captar o efeito limitado da educação sobre a ocupação, podemos utilizar um termo de interação.

Termo de interação entre educação e ocupação ilustrado em uma curva salarial.

Se você olhar para a equação salarial, ela se tornará:

Equação salarial estendida com um termo de interação entre escolaridade e ocupação

If Símbolo do coeficiente beta para o termo de interação é positivo, então implica que um nível adicional de educação produz um aumento maior no valor mediano de uma casa para um nível de ocupação elevado. Em outras palavras, há um efeito de interação entre educação e ocupação.

A mesma família de estimadores também alimenta o classificador linear Quando o rótulo é uma classe em vez de um preço. Neste tutorial, vamos tentar descobrir quais variáveis ​​podem ser boas candidatas para termos de interação. Vamos testar se a adição desse tipo de informação leva a uma melhor previsão de preços.

Estatísticas resumidas

Existem alguns passos que você pode seguir antes de prosseguir para o modelo. Como mencionado anteriormente, o modelo é uma generalização dos dados. A melhor prática é primeiro entender os dados e depois fazer uma previsão. Se você não conhece seus dados, suas chances de aprimorar o modelo são mínimas.

Como primeira etapa, carregue os dados como um dataframe do pandas e crie um conjunto de treinamento e um conjunto de testes.

Dica: Para este tutorial, você precisa ter o matplotlib e o seaborn instalados. PythonVocê pode instalar um Python pacote em tempo real com Jupyter. Você Não deveria fazer isso

!conda install -- yes matplotlib

mas a

import sys
!{sys.executable} -m pip install matplotlib # Already installed
!{sys.executable} -m pip install seaborn 

Observe que esta etapa não é necessária se você tiver o matplotlib e o seaborn instalados.

Matplotlib é a biblioteca para criar um gráfico em PythonO Seaborn é uma biblioteca de visualização estatística construída sobre o matplotlib. Ele fornece emtracEnredos envolventes e belíssimos.

O código abaixo importa as bibliotecas necessárias.

import pandas as pd
from sklearn import datasets
import tensorflow as tf
from sklearn.datasets import load_boston
import numpy as np

A biblioteca sklearn inclui o conjunto de dados de Boston. Você pode chamar sua API para importar os dados.

Nota de versão: load_boston foi descontinuado no scikit-learn 1.0 e removido no scikit-learn 1.2 Porque o conjunto de dados codifica uma característica racialmente carregada. Em uma instalação atual, use buscar_moradias_na_califórnia Em vez disso, carregue o arquivo bruto você mesmo. O fluxo de trabalho mostrado abaixo permanece inalterado; apenas o carregador é diferente.

boston = load_boston()
df = pd.DataFrame(boston.data)

Os nomes das funcionalidades são armazenados no objeto feature_names como uma matriz.

boston.feature_names

saída

array(['CRIM', 'ZN', 'INDUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD','TAX', 'PTRATIO', 'B', 'LSTAT'], dtype='<U7')

Você pode renomear as colunas.

df.columns = boston.feature_names
df['PRICE'] = boston.target
df.head(2)

As duas primeiras linhas do DataFrame de Boston após renomear as colunas.

Você converte a variável CHAS como uma variável de string e a rotula com sim se CHAS = 1 e não se CHAS = 0

df['CHAS'] = df['CHAS'].map({1:'yes', 0:'no'})
df['CHAS'].head(5)
0    no
1    no
2    no
3    no
4    no
Name: CHAS, dtype: object

Com pandas, é simples dividir o conjunto de dados. Você divide aleatoriamente o conjunto de dados com 80% de conjunto de treinamento e 20% de conjunto de teste. Pandas Possui uma função de amostragem integrada para dividir um quadro de dados.

O primeiro parâmetro frac é um valor de 0 a 1. Você o define como 0.8 para selecionar aleatoriamente 80% do quadro de dados.

O parâmetro `random_state` corrige o embaralhamento, garantindo que as mesmas linhas sejam retornadas para todos.

### Create train/test set
df_train=df.sample(frac=0.8,random_state=200)
df_test=df.drop(df_train.index)

Você pode obter a forma dos dados. Deveria ser:

  • Conjunto de trem: 506*0.8 = 405
  • Conjunto de teste: 506*0.2 = 101
print(df_train.shape, df_test.shape)

saída

(405, 14) (101, 14)
df_test.head(5)

saída

CRIME ZN INDUS CHAS NOX RM Idade DIS RAD IMPOSTO PTRAÇÃO B LSTAT PREÇO
0 0.00632 18.0 2.31 não 0.538 6.575 65.2 4.0900 1.0 296.0 15.3 396.90 4.98 24.0
1 0.02731 0.0 7.07 não 0.469 6.421 78.9 4.9671 2.0 242.0 17.8 396.90 9.14 21.6
3 0.03237 0.0 2.18 não 0.458 6.998 45.8 6.0622 3.0 222.0 18.7 394.63 2.94 33.4
6 0.08829 12.5 7.87 não 0.524 6.012 66.6 5.5605 5.0 311.0 15.2 395.60 12.43 22.9
7 0.14455 12.5 7.87 não 0.524 6.172 96.1 5.9505 5.0 311.0 15.2 396.90 19.15 27.1

Os dados são confusos; muitas vezes é desequilibrado e repleto de valores atípicos que prejudicam a análise e o treinamento de aprendizado de máquina.

A primeira etapa para limpar o conjunto de dados é entender onde ele precisa de limpeza. Limpar um conjunto de dados pode ser complicado, especialmente de qualquer maneira generalizável

O Google A equipe de pesquisa desenvolveu uma ferramenta para essa tarefa chamada Facetas Isso ajuda você a visualizar os dados e a segmentá-los de diversas maneiras. Este é um bom ponto de partida para compreender como o conjunto de dados está organizado.

O recurso Facets permite identificar áreas onde os dados não correspondem exatamente ao esperado.

Com exceção do aplicativo web, Google facilita a incorporação do conjunto de ferramentas em um Jupyter notebook.

Existem duas partes nas Facetas:

  • Visão geral das facetas
  • Aprofundamento das facetas

Visão geral das facetas

Visão geral de facetas fornece uma visão geral do conjunto de dados. A visão geral das facetas divide as colunas dos dados em linhas de informações importantes, mostrando

  1. a porcentagem de observação perdida
  2. valores mínimo e máximo
  3. estatísticas como média, mediana e desvio padrão.
  4. Ele também adiciona uma coluna que mostra a porcentagem de valores zero, o que é útil quando a maioria dos valores é zero.
  5. É possível ver essas distribuições no conjunto de dados de teste, bem como no conjunto de treinamento para cada recurso. Isso significa que você pode verificar se o teste tem uma distribuição semelhante aos dados de treinamento.

Este é pelo menos o mínimo a ser feito antes de qualquer tarefa de aprendizado de máquina. Com esta ferramenta você não perde esta etapa crucial e destaca algumas anormalidades.

Aprofundamento das facetas

O Facets Deep Dive é uma ferramenta incrível. Ele permite que você obtenha clareza sobre seu conjunto de dados e dê zoom para visualizar um dado específico. Isso significa que você pode filtrar os dados por linha e coluna em qualquer uma das características do conjunto de dados.

Usaremos essas duas ferramentas com o conjunto de dados de Boston.

Observação: você não pode usar Visão geral de facetas e Aprofundamento de facetas ao mesmo tempo. Você precisa limpar o notebook primeiro para trocar a ferramenta.

Antes de qualquer uma das ferramentas poder ser usada, o Facets precisa ser instalado no ambiente do notebook.

Instalar faceta

Você pode usar o aplicativo da web Facet para a maior parte da análise. Neste tutorial, você verá como usá-lo dentro de um Jupyter Caderno.

Primeiro de tudo, você precisa instalar o nbextensions. Isso é feito com este código. Você copia e cola o seguinte código no terminal da sua máquina.

pip install jupyter_contrib_nbextensions

Em seguida, você precisa clonar os repositórios no seu computador. Você tem duas opções:

Opção 1) Copie e cole este código no terminal (Recomendado)

Se você não tiver o Git instalado em sua máquina, acesse este link. URL Git para Windows página de download e siga as instruções. Quando terminar, você pode usar o comando git no terminal para usuário Mac ou prompt do Anaconda para Windows usuário

git clone https://github.com/PAIR-code/facets

Opção 2) Acesse o repositório PAIR-code/facets e baixe os repositórios.

Página do repositório de facetas do PAIR-code no GitHub

A página do repositório acima contém o botão de download usado na opção 2. Se você escolher a primeira opção, o arquivo será salvo na sua pasta de downloads. Você pode deixar o arquivo ser baixado ou arrastá-lo para outro local.

Você pode verificar onde o Facets está armazenado com esta linha de comando:

echo `pwd`/`ls facets`

Agora que localizou o Facets, você precisa instalá-lo em Jupyter Caderno. Você precisa definir o diretório de trabalho para o caminho onde as facetas estão localizadas.

Seu diretório de trabalho atual e a localização do zip do Facets devem ser os mesmos.

Terminal mostrando a pasta facets no diretório de trabalho atual.

A listagem do terminal acima confirma que o diretório `facets` está localizado no diretório de trabalho atual. Você precisa apontar o diretório de trabalho para `facets`:

cd facets

Para instalar facetas em Jupyter, você tem duas opções. Se você instalou Jupyter com Conda para todos os usuários, copie este código:

jupyter nbextension install facets-dist/

Caso contrário, use:

jupyter nbextension install facets-dist/ --user

Tudo bem, está tudo pronto. Vamos abrir a visão geral do faceta.

Visão geral do Executar Facets em Jupyter

Visão geral usa um Python script para calcular as estatísticas. Você precisa importar o script chamado generic_feature_statistics_generator para Jupyter. Não se preocupe; o script está localizado nos arquivos de facetas.

Você precisa localizar seu caminho. Isso é feito facilmente. Você abre facetas, abre o arquivo facets_overview e depois python. Copie o caminho

Caminho do arquivo facets_overview do Python.

Depois disso, volte para Jupyter, e escreva o seguinte código. Altere o caminho '/Users/Thomas/facets/facets_overview/python' para seu caminho.

# Add the facets overview python code to the python path# Add t 
import sys
sys.path.append('/Users/Thomas/facets/facets_overview/python')

Você pode importar o script com o código abaixo.

from generic_feature_statistics_generator import 
GenericFeatureStatisticsGenerator

No Windows, o mesmo código se torna

import sys
sys.path.append(r"C:\Users\Admin\Anaconda3\facets-master\facets_overview\python")

from generic_feature_statistics_generator import GenericFeatureStatisticsGenerator

Para calcular as estatísticas do recurso, você precisa usar a função GenericFeatureStatisticsGenerator(), e você usa o objeto ProtoFromDataFrames. Você pode passar o quadro de dados em um dicionário. Por exemplo, se quisermos criar uma estatística resumida para o conjunto de trens, podemos armazenar a informação em um dicionário e usá-la no objeto `ProtoFromDataFrames“

'name': 'train', 'table': df_train

Nome é o nome da tabela exibida e você usa o nome da tabela que deseja calcular o resumo. No seu exemplo, a tabela que contém os dados é df_train

# Calculate the feature statistics proto from the datasets and stringify it for use in facets overview
import base64

gfsg = GenericFeatureStatisticsGenerator()

proto = gfsg.ProtoFromDataFrames([{'name': 'train', 'table': df_train},
                                  {'name': 'test', 'table': df_test}])

#proto = gfsg.ProtoFromDataFrames([{'name': 'train', 'table': df_train}])
protostr = base64.b64encode(proto.SerializeToString()).decode("utf-8")

Por último, basta copiar e colar o código abaixo. O código vem diretamente do GitHub. Você deve ser capaz de ver isto:

Tabela de visão geral das facetas com estatísticas resumidas por recurso.

# Display the facets overview visualization for this data# Displ 
from IPython.core.display import display, HTML

HTML_TEMPLATE = """<link rel="import" href="/nbextensions/facets-dist/facets-jupyter.html" >
        <facets-overview id="elem"></facets-overview>
        <script>
          document.querySelector("#elem").protoInput = "{protostr}";
        </script>"""
html = HTML_TEMPLATE.format(protostr=protostr)
display(HTML(html))

Gráfico de correlação e grade de pares

Após verificar os dados e sua distribuição, você pode plotar uma matriz de correlação. A matriz de correlação calcula o coeficiente de Pearson. Esse coeficiente varia entre -1 e 1, onde um valor positivo indica uma correlação positiva e um valor negativo, uma correlação negativa.

Você está interessado em ver quais variáveis ​​podem ser boas candidatas para termos de interação.

Nota de versão: a máscara abaixo chama np.bool, um alias que foi descontinuado no NumPy 1.20 e removido no NumPy 1.24Em uma versão recente do NumPy, a mesma linha gera o seguinte erro: AttributeError: module 'numpy' has no attribute 'bool'; o embutido bool é a substituição direta.

## Choose important feature and further check with Dive
%matplotlib inline  
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="ticks")
# Compute the correlation matrix
corr = df.corr('pearson')
# Generate a mask for the upper triangle
mask = np.zeros_like(corr, dtype=np.bool)
mask[np.triu_indices_from(mask)] = True
# Set up the matplotlib figure
f, ax = plt.subplots(figsize=(11, 9))

# Generate a custom diverging colormap
cmap = sns.diverging_palette(220, 10, as_cmap=True)

# Draw the heatmap with the mask and correct aspect ratio
sns.heatmap(corr, mask=mask, cmap=cmap, vmax=.3, center=0,annot=True,
            square=True, linewidths=.5, cbar_kws={"shrink": .5})

saída

<matplotlib.axes._subplots.AxesSubplot at 0x1a184d6518>

Mapa de calor de correlação Seaborn das variáveis ​​de Boston

No mapa de calor acima, os quadrados mais escuros indicam correlações mais fortes. A partir da matriz, você pode ver:

  • LSTAT
  • RM

Estão fortemente correlacionados com o PREÇO. Outra característica interessante é a forte correlação positiva entre NOX e INDUS, o que significa que essas duas variáveis ​​se movem na mesma direção. Ambas também estão correlacionadas com o PREÇO. DIS também apresenta alta correlação com INDUS e NOX.

Você tem um primeiro indício de que INDUS e NOX podem ser bons candidatos para um termo de interação, e DIS também pode ser interessante para se analisar.

Você pode ir um pouco mais fundo traçando uma grade de pares. Ilustrará mais detalhadamente o mapa de correlação que você traçou antes.

A grade de pares é composta da seguinte forma:

  • Parte superior: gráfico de dispersão com linha ajustada
  • Diagonal: gráfico de densidade do kernel
  • Parte inferior: gráfico de densidade multivariada do kernel

Você se concentra em quatro variáveis ​​independentes. A escolha corresponde às variáveis ​​com forte correlação com o PREÇO.

  • INDUS
  • NOX
  • RM
  • LSTAT

além disso, o PREÇO.

Observação que o erro padrão é adicionado por padrão ao gráfico de dispersão.

attributes = ["PRICE", "INDUS", "NOX", "RM", "LSTAT"]

g = sns.PairGrid(df[attributes])
g = g.map_upper(sns.regplot, color="g")
g = g.map_lower(sns.kdeplot,cmap="Reds", shade=True, shade_lowest=False)
g = g.map_diag(sns.kdeplot)

saída

Grade de pares Seaborn de PREÇO, INDÚSTRIA, NOX, RM e LSTAT

Vamos começar pela parte superior:

  • O preço está negativamente correlacionado com INDUS, NOX e LSTAT; correlacionado positivamente com RM.
  • Existe uma ligeira não-linearidade entre LSTAT e PRICE.
  • Existe como uma linha reta quando o preço é igual a 50. A partir da descrição do conjunto de dados, PRICE foi truncado no valor de 50

Diagonal: NOX parece ter dois clusters, um em torno de 0.5 e outro em torno de 0.85.

Para saber mais sobre isso, você pode dar uma olhada na parte inferior. A Densidade Multivariada do Kernel é interessante no sentido de que colore onde está a maioria dos pontos. A diferença com o gráfico de dispersão desenha uma densidade de probabilidade, mesmo que não haja nenhum ponto no conjunto de dados para uma determinada coordenada. Quando a cor é mais forte, indica uma alta concentração de pontos ao redor desta área.

Se você verificar a densidade multivariada para INDUS e NOX, poderá ver a correlação positiva e os dois clusters. Quando a participação da indústria é superior a 18, a concentração de óxidos nítricos fica acima de 0.6.

Você pode pensar em adicionar uma interação entre INDUS e NOX na relação linear.

Por fim, você pode usar a segunda ferramenta criada por GoogleAnálise Detalhada de Facetas. A interface está dividida em quatro seções principais. A área central exibe os dados em zoom. Na parte superior do painel, há um menu suspenso onde você pode alterar a disposição dos dados, controlando o facetamento, o posicionamento e a cor. À direita, há uma visualização detalhada de uma linha de dados específica. Isso significa que você pode clicar em qualquer ponto de dados na visualização central para ver os detalhes daquele ponto de dados em particular.

Durante a etapa de visualização dos dados, você está interessado em procurar a correlação de pares entre a variável independente no preço da casa. No entanto, envolve pelo menos três variáveis, e os gráficos 3D são complicados de trabalhar.

Uma maneira de resolver esse problema é criar uma variável categórica. Ou seja, podemos criar um gráfico 2D e colorir os pontos. Podemos dividir a variável PREÇO em quatro categorias, sendo cada categoria um quartil (por exemplo, 0.25, 0.5, 0.75). Chamamos essa nova variável de Q_PREÇO.

## Check non linearity with important features
df['Q_PRICE'] =  pd.qcut(df['PRICE'], 4, labels=["Lowest", "Low", "Upper", "upper_plus"])
## Show non linearity between RM and LSTAT
ax = sns.lmplot(x="DIS", y="INDUS", hue="Q_PRICE", data=df, fit_reg = False,palette="Set3")

Gráfico de dispersão de DIS em relação a INDUS, colorido por quartil de preço.

Análise detalhada de facetas

Para abrir o Deep Dive, você precisa transformar os dados em formato JSON. O Pandas possui um método para isso: chame o método `to_json` no DataFrame.

A primeira linha de código define o tamanho do sprite de acordo com o número de linhas que o conjunto de dados contém.

df['Q_PRICE'] =  pd.qcut(df['PRICE'], 4, labels=["Lowest", "Low", "Upper", "upper_plus"])
sprite_size = 32 if len(df.index)>50000 else 64
jsonstr = df.to_json(orient='records')

O código abaixo vem de Google GitHub. Depois de executar o código, você deverá ver o seguinte:

Análise detalhada das facetas do conjunto de dados de Boston.

# Display thde Dive visualization for this data
from IPython.core.display import display, HTML

# Create Facets template  
HTML_TEMPLATE = """<link rel="import" href="/nbextensions/facets-dist/facets-jupyter.html">
        <facets-dive sprite-image-width="{sprite_size}" sprite-image-height="{sprite_size}" id="elem" height="600"></facets-dive>
        <script>
          document.querySelector("#elem").data = {jsonstr};
        </script>"""

# Load the json dataset and the sprite_size into the template
html = HTML_TEMPLATE.format(jsonstr=jsonstr, sprite_size=sprite_size)

# Display the template
display(HTML(html))

Você está interessado em ver se existe uma conexão entre a taxa da indústria, a concentração de óxidos, a distância até o centro de empregos e o preço da casa.

Para isso, primeiro você divide os dados por faixa e cor do setor com o quartil de preço:

  • Selecione facetar X e escolha INDUS.
  • Selecione Exibir e escolha DIS. Ele irá colorir os pontos com o quartil do preço da casa

Aqui, cores mais escuras significam que a distância até o primeiro centro de emprego é maior.

Até agora, mostra novamente o que você sabe, taxa mais baixa da indústria, preço mais alto. Agora você pode ver a divisão por INDUX, por NOX.

Selecione facetar Y e escolha NOX.

Agora você pode ver que as casas distantes do primeiro centro de emprego têm a menor participação na indústria e, portanto, a menor concentração de óxidos. Se você optar por exibir o tipo com Q_PRICE e ampliar o canto inferior esquerdo, poderá ver que tipo de preço é.

Você tem outra dica de que a interação entre IND, NOX e DIS pode ser bons candidatos para melhorar o modelo.

A análise exploratória identificou duas interações candidatas, portanto, o próximo passo é testá-las em um modelo real.

Regressão Linear com TensorFlow

Nesta seção, você estimará o modelo de regressão linear com o TensorFlow API do Estimador. O procedimento será o seguinte:

  • Prepare os dados
  • Estimar um modelo de benchmark: sem interação
  • Estimar um modelo com interação

Nota de versão: da tf-estimator O pacote foi lançado em sua versão final com o TensorFlow 2.15 e está ausente a partir do TensorFlow 2.16. tf.estimator.LinearRegressor Funciona apenas no TensorFlow 1.x, a menos que você migre para um modelo linear Keras.

Lembre-se, o objetivo do aprendizado de máquina é minimizar o erro. Nesse caso, o modelo com o menor erro quadrático médio será o vencedor. O estimador do TensorFlow calcula essa métrica automaticamente.

Dados de preparação

Na maioria dos casos, você precisa transformar seus dados. É por isso que a Visão Geral de Facetas é tão interessante. Pelas estatísticas resumidas, você viu que existem outliers. Esses valores afetam as estimativas porque não se parecem com a população que você está analisando. Outliers geralmente enviesam os resultados. Por exemplo, um outlier positivo tende a superestimar o coeficiente.

Uma boa solução para lidar com esse problema é padronizar a variável. Padronização significa um desvio padrão de um e uma média de zero. O processo de padronização envolve duas etapas. Primeiramente, ele substitui a média por um desvio padrão de um e uma média de zero.tracEm seguida, t é o valor médio da variável. Depois, divide-se pelo desvio padrão para que a distribuição tenha um desvio padrão unitário.

A biblioteca scikit-learn É útil padronizar as variáveis. Você pode usar o módulo de pré-processamento com a escala de objeto para esse fim.

Você pode usar a função abaixo para dimensionar um conjunto de dados. Observe que você não dimensiona a coluna do rótulo e as variáveis ​​categóricas.

from sklearn import preprocessing
def standardize_data(df): 
    X_scaled = preprocessing.scale(df[['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
       'TAX', 'PTRATIO', 'B', 'LSTAT']])
    X_scaled_df = pd.DataFrame(X_scaled, columns = ['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD',
       'TAX', 'PTRATIO', 'B', 'LSTAT'])
    df_scale = pd.concat([X_scaled_df,
                       df['CHAS'],
                       df['PRICE']],axis=1, join='inner')
    return df_scale

Você pode usar a função para construir o conjunto de treinamento/teste dimensionado.

df_train_scale = standardize_data(df_train)
df_test_scale = standardize_data(df_test)

Regressão básica:Benchmark

Primeiro de tudo, você treina e testa um modelo sem interação. O objetivo é ver a métrica de desempenho do modelo.

A forma de treinar o modelo é exatamente como no tutorial sobre o API de alto nível. Você usará o estimador LinearRegressor do TensorFlow.

Como lembrete, você precisa escolher:

  • os recursos para colocar no modelo
  • transformar os recursos
  • construir o regressor linear
  • construir a função input_fn
  • treine o modelo
  • testar o modelo

Você utiliza todas as variáveis ​​do conjunto de dados para treinar o modelo. No total, existem doze variáveis ​​contínuas e uma variável categórica.

## Add features to the bucket: 
### Define continuous list
CONTI_FEATURES  = ['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD','TAX', 'PTRATIO', 'B', 'LSTAT']
CATE_FEATURES = ['CHAS']

Você converte os recursos em uma coluna numérica ou coluna categórica

continuous_features = [tf.feature_column.numeric_column(k) for k in CONTI_FEATURES]
#categorical_features = tf.feature_column.categorical_column_with_hash_bucket(CATE_FEATURES, hash_bucket_size=1000)
categorical_features = [tf.feature_column.categorical_column_with_vocabulary_list('CHAS', ['yes','no'])]

Você cria o modelo com o linearRegressor. Você armazena o modelo na pasta train_Boston

model = tf.estimator.LinearRegressor(    
	model_dir="train_Boston",     
    feature_columns=categorical_features + continuous_features)

saída

INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'train_Boston', '_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 0x1a19e76ac8>, '_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}

Cada coluna nos dados de treino ou teste é convertida em um Tensor com a função get_input_fn.

FEATURES = ['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD','TAX', 'PTRATIO', 'B', 'LSTAT', 'CHAS']
LABEL= 'PRICE'
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ê estima o modelo nos dados do trem.

model.train(input_fn=get_input_fn(df_train_scale, 
                                      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 train_Boston/model.ckpt.
INFO:tensorflow:loss = 56417.703, step = 1
INFO:tensorflow:global_step/sec: 144.457
INFO:tensorflow:loss = 76982.734, step = 101 (0.697 sec)
INFO:tensorflow:global_step/sec: 258.392
INFO:tensorflow:loss = 21246.334, step = 201 (0.383 sec)
INFO:tensorflow:global_step/sec: 227.998
INFO:tensorflow:loss = 30534.78, step = 301 (0.439 sec)
INFO:tensorflow:global_step/sec: 210.739
INFO:tensorflow:loss = 36794.5, step = 401 (0.477 sec)
INFO:tensorflow:global_step/sec: 234.237
INFO:tensorflow:loss = 8562.981, step = 501 (0.425 sec)
INFO:tensorflow:global_step/sec: 238.1
INFO:tensorflow:loss = 34465.08, step = 601 (0.420 sec)
INFO:tensorflow:global_step/sec: 237.934
INFO:tensorflow:loss = 12241.709, step = 701 (0.420 sec)
INFO:tensorflow:global_step/sec: 220.687
INFO:tensorflow:loss = 11019.228, step = 801 (0.453 sec)
INFO:tensorflow:global_step/sec: 232.702
INFO:tensorflow:loss = 24049.678, step = 901 (0.432 sec)
INFO:tensorflow:Saving checkpoints for 1000 into train_Boston/model.ckpt.
INFO:tensorflow:Loss for final step: 23228.568.


<tensorflow.python.estimator.canned.linear.LinearRegressor at 0x1a19e76320>

Por fim, você estima o desempenho do modelo no conjunto de testes

model.evaluate(input_fn=get_input_fn(df_test_scale, 
                                      num_epochs=1,
                                      n_batch = 128,
                                      shuffle=False),
                                      steps=1000)

saída

INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-05-29-02:40:43
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train_Boston/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Finished evaluation at 2018-05-29-02:40:43
INFO:tensorflow:Saving dict for global step 1000: average_loss = 86.89361, global_step = 1000, loss = 1650.9785


{'average_loss': 86.89361, 'global_step': 1000, 'loss': 1650.9785}

A perda do modelo é 1650.9785. Esta é a métrica a ser superada na próxima seção

Melhorar o modelo: termo de interação

Durante a primeira parte do tutorial, você observou uma relação interessante entre as variáveis. As diferentes técnicas de visualização revelaram que INDUS e NOX estão interligados e amplificam o efeito um do outro sobre o preço. A interação entre INDUS e NOX não só afeta o preço, como esse efeito é ainda mais forte quando há interação com DIS.

Chegou a hora de generalizar essa ideia e ver se é possível melhorar a previsão do modelo.

Você precisa adicionar duas novas colunas a cada conjunto de dados: treino e teste. Para isso, crie uma função para calcular o termo de interação e outra para calcular o termo de interação tripla. Cada função gera uma única coluna. Após a criação das novas variáveis, você pode concatená-las aos conjuntos de dados de treino e teste.

Primeiro de tudo, é necessário criar uma nova variável para a interação entre INDUS e NOX.

A função abaixo retorna dois dataframes, train e test, com a interação entre var_1 e var_2, no seu caso INDUS e NOX.

def interaction_term(var_1, var_2, name):
    t_train = df_train_scale[var_1]*df_train_scale[var_2]
    train = t_train.rename(name)
    t_test = df_test_scale[var_1]*df_test_scale[var_2]
    test = t_test.rename(name)
    return train, test

Você armazena as duas novas colunas

interation_ind_ns_train, interation_ind_ns_test= interaction_term('INDUS', 'NOX', 'INDUS_NOS')
interation_ind_ns_train.shape
(325,)

Em segundo lugar, você cria uma segunda função para calcular o termo de interação tripla.

def triple_interaction_term(var_1, var_2,var_3, name):
    t_train = df_train_scale[var_1]*df_train_scale[var_2]*df_train_scale[var_3]
    train = t_train.rename(name)
    t_test = df_test_scale[var_1]*df_test_scale[var_2]*df_test_scale[var_3]
    test = t_test.rename(name)
    return train, test
interation_ind_ns_dis_train, interation_ind_ns_dis_test= triple_interaction_term('INDUS', 'NOX', 'DIS','INDUS_NOS_DIS')

Agora que você tem todas as colunas necessárias, pode adicioná-las ao conjunto de dados de treinamento e teste. Você nomeia esses dois novos dataframes:

  • df_train_new
  • df_test_new
df_train_new = pd.concat([df_train_scale,
                          interation_ind_ns_train,
                          interation_ind_ns_dis_train],
                         axis=1, join='inner')
df_test_new = pd.concat([df_test_scale,
                         interation_ind_ns_test,
                         interation_ind_ns_dis_test],
                         axis=1, join='inner')
df_train_new.head(5)

saída

DataFrame de treinamento com as colunas INDUS_NOS e INDUS_NOS_DIS adicionadas.

Pronto: você pode estimar o novo modelo com os termos de interação e ver como fica a métrica de desempenho.

CONTI_FEATURES_NEW  = ['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD','TAX', 'PTRATIO', 'B', 'LSTAT',
                       'INDUS_NOS', 'INDUS_NOS_DIS']
### Define categorical list
continuous_features_new = [tf.feature_column.numeric_column(k) for k in CONTI_FEATURES_NEW]
model = tf.estimator.LinearRegressor(
    model_dir="train_Boston_1", 
    feature_columns= categorical_features + continuous_features_new)

saída

INFO:tensorflow:Using default config.
INFO:tensorflow:Using config: {'_model_dir': 'train_Boston_1', '_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 0x1a1a5d5860>, '_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}

Code

FEATURES = ['CRIM', 'ZN', 'INDUS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD','TAX', 'PTRATIO', 'B', 'LSTAT','INDUS_NOS', 'INDUS_NOS_DIS','CHAS']
LABEL= 'PRICE'
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)
model.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 train_Boston_1/model.ckpt.
INFO:tensorflow:loss = 56417.703, step = 1
INFO:tensorflow:global_step/sec: 124.844
INFO:tensorflow:loss = 65522.3, step = 101 (0.803 sec)
INFO:tensorflow:global_step/sec: 182.704
INFO:tensorflow:loss = 15384.148, step = 201 (0.549 sec)
INFO:tensorflow:global_step/sec: 208.189
INFO:tensorflow:loss = 22020.305, step = 301 (0.482 sec)
INFO:tensorflow:global_step/sec: 213.855
INFO:tensorflow:loss = 28208.812, step = 401 (0.468 sec)
INFO:tensorflow:global_step/sec: 209.758
INFO:tensorflow:loss = 7606.877, step = 501 (0.473 sec)
INFO:tensorflow:global_step/sec: 196.618
INFO:tensorflow:loss = 26679.76, step = 601 (0.514 sec)
INFO:tensorflow:global_step/sec: 196.472
INFO:tensorflow:loss = 11377.163, step = 701 (0.504 sec)
INFO:tensorflow:global_step/sec: 172.82
INFO:tensorflow:loss = 8592.07, step = 801 (0.578 sec)
INFO:tensorflow:global_step/sec: 168.916
INFO:tensorflow:loss = 19878.56, step = 901 (0.592 sec)
INFO:tensorflow:Saving checkpoints for 1000 into train_Boston_1/model.ckpt.
INFO:tensorflow:Loss for final step: 19598.387.


<tensorflow.python.estimator.canned.linear.LinearRegressor at 0x1a1a5d5e10>
model.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.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Starting evaluation at 2018-05-29-02:41:14
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Restoring parameters from train_Boston_1/model.ckpt-1000
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Finished evaluation at 2018-05-29-02:41:14
INFO:tensorflow:Saving dict for global step 1000: average_loss = 79.78876, global_step = 1000, loss = 1515.9863


{'average_loss': 79.78876, 'global_step': 1000, 'loss': 1515.9863}

A nova perda é 1515.9863. Apenas adicionando duas novas variáveis, você conseguiu diminuir a perda. Isso significa que você pode fazer uma previsão melhor do que com o modelo de benchmark.

Modelo Conjunto de características Diretório do modelo perda_média fora
referência 12 colunas contínuas padronizadas mais CHAS trem_Boston 86.89361 1650.9785
Com interação Benchmark mais INDUS_NOS e INDUS_NOS_DIS trem_Boston_1 79.78876 1515.9863

Ambos os valores provêm da mesma divisão de teste de 101 linhas, portanto, a queda de aproximadamente 8% na perda média é atribuível apenas às duas colunas de interação.

Perguntas Frequentes

Foi descontinuado no scikit-learn 1.0 e removido na versão 1.2. O conjunto de dados contém uma característica baseada na suposição de autosegregação racial e preços de imóveis, e o estudo original nunca validou sua premissa sobre a qualidade do ar. Imóveis na Califórnia ou em Ames são os substitutos usuais.

Um termo polinomial eleva ao quadrado ou ao cubo uma variável para moldar sua própria curva. Uma interação multiplica duas variáveis ​​diferentes, de modo que a inclinação de uma depende do nível da outra. Este tutorial constrói o segundo tipo, INDUS vezes NOX.

Procure pares que se correlacionem entre si e com o alvo. O mapa de calor de Pearson e a grade de pares fazem isso visualmente; aqui, INDUS e NOX se agrupam e ambos track PREÇO, que é o sinal que justifica o cruzamento deles.

Bibliotecas automatizadas de engenharia de recursos geram transformações e cruzamentos candidatos, avaliam cada um em relação a um conjunto de validação e mantêm apenas aqueles que reduzem o erro. Isso substitui a leitura manual do mapa de calor mostrada aqui, embora ainda seja necessário que um humano verifique o significado das colunas geradas.

O Copilot lida bem com código repetitivo de plotagem — grades de pares, mapas de calor mascarados, modelos HTML para Facetas. Verifique os argumentos sugeridos, pois o seaborn renomeou vários deles e o Copilot combina assinaturas antigas e atuais sem problemas.

Não. A perda deve ser comparada na mesma amostra reservada, como é o caso aqui. Uma perda que incide apenas sobre os dados de treinamento indica sobreajuste, e adicionar colunas quase sempre melhora o ajuste do conjunto de treinamento, independentemente de elas conterem ou não informações relevantes.

A máscara usa `np.bool`, um alias obsoleto no NumPy 1.20 e removido no 1.24. Instalações recentes geram um erro `AttributeError`. Substituir pelo tipo `bool` nativo mantém o comportamento idêntico; `np.bool_` também funciona se você precisar do tipo escalar do NumPy.

CHAS é uma variável categórica (sim ou não) e PRICE é o rótulo. Centralizar e dimensionar uma variável dummy dificulta a leitura do seu coeficiente sem alterar o ajuste, e dimensionar o rótulo simplesmente redimensionaria a perda relatada. Apenas os doze preditores contínuos são padronizados.

Resuma esta postagem com: