APARTAMENTOS_E_SALAS / aptos_2026.py
ESJL's picture
Update aptos_2026.py
6914eb8 verified
import pandas as pd
import numpy as np
import joblib
import seaborn as sns
import matplotlib.pyplot as plt
import xgboost as xgb
import warnings
import gradio as gr
from reportlab.lib.pagesizes import A4
from reportlab.platypus import Spacer, Frame, PageTemplate, BaseDocTemplate, Paragraph
from reportlab.lib.styles import getSampleStyleSheet
inf_scaler_in = joblib.load("dados/apartamentos/input_scaler_ape_DEZ2024.save")
inf_scaler_out = joblib.load("dados/apartamentos/output_scaler_ape_DEZ2024.save")
inf_model_v1 = xgb.Booster(); inf_model_v1.load_model("dados/apartamentos/APARTAMENTO_2020_a_2025.model")
inf_model_v2 = xgb.Booster(); inf_model_v2.load_model("dados/apartamentos/APARTAMENTOS_RESIDUAL_2026.model")
# Função para gerar PDF
def gerar_pdf(dados_imovel, valor_unit, valor_total):
filename = 'relatorio.pdf'
doc = BaseDocTemplate(filename, pagesize=A4)
styles = getSampleStyleSheet()
story = [
Paragraph("Relatório - Modelo Híbrido 2026", styles['Title']),
Spacer(1, 12),
Paragraph(f"<b>Ano Base:</b> {dados_imovel['ano_ref']}", styles['Normal']),
Paragraph(f"<b>Características:</b> {dados_imovel['area']} m², Padrão {dados_imovel['padrao']}, Ano Const. {dados_imovel['ano_c']}", styles['Normal']),
Paragraph(f"<b>Localização (UTM):</b> X={dados_imovel['x']}, Y={dados_imovel['y']}", styles['Normal']),
Spacer(1, 20),
Paragraph(f"<b>Valor Unitário Calculado:</b> R$ {valor_unit:,.2f}/m²", styles['Heading2']),
Paragraph(f"<b>Valor Total Estimado:</b> R$ {valor_total:,.2f}", styles['Heading2']),
]
frame = Frame(doc.leftMargin, doc.bottomMargin, doc.width, doc.height, id='normal')
template = PageTemplate(id='base', frames=frame)
doc.addPageTemplates([template])
doc.build(story)
return filename
# FUNÇÃO PRINCIPAL DA INTERFACE
def avaliar_imovel(fon_str, x, y, rh, ano_c, atotal, andar, padrao, ano_ref):
# 1. Mapeamento de Features (Feature Engineering em Tempo Real)
is_oferta = 1 if fon_str == "Oferta" else 0
# Padrão (One Hot Encoding manual)
# Se for A ou B, C/D/E permanecem 0
dummies_padrao = {'C': 0, 'D': 0, 'E': 0}
if padrao in dummies_padrao:
dummies_padrao[padrao] = 1
# Dummies de Ano V1 (2019-2024)
anos_v1 = {f'ANO_{a}': (1 if str(ano_ref) == str(a) else 0) for a in range(2019, 2025)}
# Dummy de Ano V2 (2025)
is_2025 = 1 if str(ano_ref) == '2025' else 0
# Montagem do DataFrame Input (Single Row)
# Atenção aos Logs!
input_dict = {
'FON': [is_oferta],
'ANO_CONST': [float(ano_c)],
'ANDAR': [float(andar)],
'X': [float(x)],
'Y': [float(y)],
'ATOTAL': [np.log(float(atotal))], # Log Transform
'RH': [np.log(float(rh))], # Log Transform
**dummies_padrao,
**anos_v1
}
# Lista de colunas na ordem correta do V1
cols_v1 = [
'FON', 'ANO_CONST', 'ANDAR', 'X', 'Y', 'ATOTAL', 'RH',
'ANO_2019', 'ANO_2020', 'ANO_2021', 'ANO_2022', 'ANO_2023', 'ANO_2024',
'C', 'D', 'E'
]
df_inferencia = pd.DataFrame(input_dict)
# Garante ordem e preenche ausentes se houver
for c in cols_v1:
if c not in df_inferencia.columns: df_inferencia[c] = 0
df_inferencia = df_inferencia[cols_v1]
try:
# 2. Escalonamento V1
array_scaled = inf_scaler_in.transform(df_inferencia)
# 3. Predição Baseline (V1)
dmatrix_base = xgb.DMatrix(array_scaled, feature_names=cols_v1)
pred_base = inf_model_v1.predict(dmatrix_base)
# 4. Lógica de Decisão Temporal (Compatibilidade Reversa)
# Se o ano for anterior a 2025, não usamos o modelo residual para manter consistência histórica.
final_pred_scaled = pred_base
if int(ano_ref) >= 2025:
# Prepara entrada V2 (V1 Scaled + Coluna ANO_2025)
# Adiciona a coluna 2025 (que é 1 neste caso)
input_v2 = np.hstack([array_scaled, [[is_2025]]])
dmatrix_v2 = xgb.DMatrix(input_v2)
dmatrix_v2.set_base_margin(pred_base)
# Predição Híbrida
final_pred_scaled = inf_model_v2.predict(dmatrix_v2)
# 5. Pós-Processamento (Inverse Transform)
# Inverte Scaler de Output
pred_log = inf_scaler_out.inverse_transform(np.array(final_pred_scaled).reshape(-1,1))
# Inverte Log (Exp)
val_unit_real = np.exp(pred_log).flatten()[0]
# Cálculos Finais
total_val = val_unit_real * float(atotal)
# Gera PDF
dados_contexto = {
'ano_ref': ano_ref, 'area': atotal, 'padrao': padrao,
'ano_c': ano_c, 'x': x, 'y': y
}
path_pdf = gerar_pdf(dados_contexto, val_unit_real, total_val)
msg = f"Valor Unitário: R$ {val_unit_real:,.2f}/m²\nValor Total: R$ {total_val:,.2f}"
return msg, path_pdf
except Exception as e:
return f"Erro Crítico: {str(e)}", None
def load_inputs():
in_fon = gr.Radio(["Transação", "Oferta"], label="Fonte de Dados", value="Transação")
in_x = gr.Number(label="Coord X (UTM)", value=281554)
in_y = gr.Number(label="Coord Y (UTM)", value=1675418)
in_rh = gr.Number(label="Região Homogênea", value=120)
in_area = gr.Number(label="Área Total (m²)", value=60)
in_andar = gr.Number(label="Andar", value=4)
in_ano_c = gr.Number(label="Ano Construção", value=2020)
in_padrao = gr.Dropdown(["C", "D", "E"], label="Padrão", value="C")
in_ano_ref = gr.Dropdown([str(i) for i in range(2019, 2026)], label="Ano Base", value="2025")
return [in_fon, in_x, in_y, in_rh, in_ano_c, in_area, in_andar, in_padrao, in_ano_ref]
title = 'Apartamentos - XGBoost Regressor - 2026'
description = f"""
# <p style="text-align: center;">Modelo para Apartamentos - XGBoost Regressor - 2026</p>
<p style="text-align: center;">Dados referentes aos anos 2019 a 2025.</p>
<hr style="color: #333; background-color: #333; height: 1px; border: none;">
"""