← Blog

Do notebook ao Streamlit: construindo um modelo de score de crédito

2023-11-20PythonScikit-learnStreamlit

O que é um score de crédito e por que importa

Score de crédito é um modelo que estima a probabilidade de inadimplência de um cliente com base em variáveis históricas — renda, idade, histórico de pagamentos, utilização de limite, entre outras. Bancos e fintechs usam esse número para decidir aprovação, taxa de juros e limite de crédito.

Em ciência de dados, o desafio não termina no notebook com um AUC aceitável. O modelo precisa ser reprodutível, versionado e acessível para analistas, área de negócio ou outros sistemas. Uma aplicação Streamlit é um passo intermediário ideal: valida o modelo com usuários reais antes de integrar em APIs ou batch scoring.

Este post cobre o caminho completo — do treino com pipeline scikit-learn até uma interface onde qualquer pessoa insere dados e recebe uma predição com explicação básica.

Estrutura de um projeto de score

Um projeto de crédito tabular segue uma estrutura previsível:

  1. Dados — features numéricas e categóricas, target binário (inadimplente / não)
  2. Pré-processamento — imputação de missing, encoding de categóricas, escalonamento se necessário
  3. Modelo — tipicamente Logistic Regression, Random Forest ou XGBoost
  4. Avaliação — AUC-ROC, AUC-PR, KS, matriz de confusão na classe minoritária
  5. Deploy — serialização do pipeline e interface ou API

A decisão crítica é empacotar pré-processamento e modelo em um único pipeline. Se você salvar só o classificador, o deploy quebra na primeira predição — as features chegam cruas e o modelo espera dados transformados.

Pré-processamento e pipeline de treino

O exemplo abaixo usa um dataset sintético com estrutura típica de crédito. Em produção, substitua pelo seu CSV real mantendo a mesma lógica de pipeline.

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score, classification_report
import joblib

# Exemplo: carregar dados reais
# df = pd.read_csv("credit_applications.csv")

numeric_features = ["income", "age", "credit_utilization", "months_employed"]
categorical_features = ["employment_type", "housing_status"]

X = df[numeric_features + categorical_features]
y = df["default"]

numeric_transformer = Pipeline([
    ("imputer", SimpleImputer(strategy="median")),
    ("scaler", StandardScaler()),
])

categorical_transformer = Pipeline([
    ("imputer", SimpleImputer(strategy="most_frequent")),
    ("encoder", OneHotEncoder(handle_unknown="ignore")),
])

preprocessor = ColumnTransformer([
    ("num", numeric_transformer, numeric_features),
    ("cat", categorical_transformer, categorical_features),
])

model_pipeline = Pipeline([
    ("preprocessor", preprocessor),
    ("classifier", RandomForestClassifier(
        n_estimators=200,
        class_weight="balanced",
        random_state=42,
    )),
])

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, stratify=y, random_state=42
)

model_pipeline.fit(X_train, y_train)
y_proba = model_pipeline.predict_proba(X_test)[:, 1]

print("AUC-ROC:", roc_auc_score(y_test, y_proba))
print(classification_report(y_test, model_pipeline.predict(X_test)))

Três detalhes importantes:

  • handle_unknown="ignore" no OneHotEncoder evita erro quando uma categoria nova aparece em produção
  • class_weight="balanced" ajuda com desbalanceamento sem reamostragem separada
  • O pipeline inteiro é o artefato — não salve transformações e modelo em arquivos distintos

Serialização do modelo

Após validar o modelo, serialize o pipeline completo com joblib:

joblib.dump(model_pipeline, "models/credit_score_v1.joblib")

# Carregar em outro script ou app
loaded_model = joblib.load("models/credit_score_v1.joblib")
score = loaded_model.predict_proba(single_row)[:, 1][0]

Versione o arquivo (credit_score_v1, v2, etc.) e registre métricas de validação junto — em projetos maiores, MLflow ou DVC fazem isso de forma estruturada. Para um portfolio ou MVP, um diretório models/ com README descrevendo data de treino e AUC já é suficiente.

Interface com Streamlit

Streamlit transforma o modelo em uma aplicação web em poucas dezenas de linhas. A estrutura básica: sidebar com inputs, botão de predição, resultado com score e classificação.

import streamlit as st
import pandas as pd
import joblib

st.set_page_config(page_title="Score de Crédito", layout="centered")
st.title("Simulador de Score de Crédito")

@st.cache_resource
def load_model():
    return joblib.load("models/credit_score_v1.joblib")

model = load_model()

st.sidebar.header("Dados do solicitante")
income = st.sidebar.number_input("Renda mensal (R$)", min_value=0, value=5000)
age = st.sidebar.number_input("Idade", min_value=18, max_value=100, value=35)
credit_util = st.sidebar.slider("Utilização do crédito (%)", 0, 100, 30)
months_employed = st.sidebar.number_input("Meses no emprego atual", min_value=0, value=24)
employment = st.sidebar.selectbox(
    "Tipo de emprego", ["CLT", "autonomo", "aposentado", "desempregado"]
)
housing = st.sidebar.selectbox(
    "Situação habitacional", ["propria", "alugada", "financiada", "familiar"]
)

if st.button("Calcular score"):
    input_data = pd.DataFrame([{
        "income": income,
        "age": age,
        "credit_utilization": credit_util,
        "months_employed": months_employed,
        "employment_type": employment,
        "housing_status": housing,
    }])

    proba = model.predict_proba(input_data)[0, 1]
    score_display = int((1 - proba) * 1000)  # score invertido: maior = melhor

    st.metric("Score", score_display)
    st.progress(proba)

    if proba < 0.3:
        st.success("Baixo risco de inadimplência")
    elif proba < 0.6:
        st.warning("Risco moderado — análise adicional recomendada")
    else:
        st.error("Alto risco de inadimplência")

@st.cache_resource carrega o modelo uma vez por sessão — evita releitura do disco a cada interação. A conversão de probabilidade para score 0–1000 é convenção de mercado (estilo bureau), mas a escala exata depende da política de cada instituição.

Para rodar localmente:

streamlit run app.py

Além do básico: pontos de atenção

Levar um score de crédito para além do protótipo exige cuidados adicionais:

  • Validação temporal — em crédito, dados futuros não podem vazar para o treino; use split por data, não aleatório
  • Fairness e viés — variáveis como bairro ou gênero podem introduzir discriminação; revise features com área jurídica e compliance
  • Explicabilidade — SHAP ou feature importance ajudam analistas a entender por que um score foi alto ou baixo
  • Monitoramento de drift — distribuição de features muda com o tempo; score calibrado em 2023 pode degradar em 2025
  • Inputs inválidos — valide ranges na interface (idade negativa, renda absurda) antes de chamar o modelo

Armadilhas comuns no notebook → Streamlit:

  • Salvar só o .fit() final sem o ColumnTransformer — predição falha em produção
  • Hardcodar categorias no selectbox que não batem com o treino — gera encoding inconsistente
  • Exibir probabilidade bruta sem contexto — usuários de negócio preferem score ou faixas de risco
  • Não testar com @st.cache_resource após retreinar — limpe cache ou reinicie o app

Conclusão

Um score de crédito em produção começa com um pipeline scikit-learn que une pré-processamento e classificador, serializado como artefato único. Streamlit é a forma mais rápida de validar esse artefato com usuários antes de construir APIs ou pipelines batch.

O fluxo prático: treine com Pipeline + ColumnTransformer, avalie com AUC-PR na classe minoritária, salve com joblib, monte a interface com inputs que espelham as features de treino. O próximo passo natural é enriquecer as features — o tema do post sobre feature engineering para modelos tabulares.

Referencias

  1. Scikit-learn — Pipeline
  2. Scikit-learn — ColumnTransformer
  3. Streamlit — Documentação
  4. Streamlit — st.cache_resource
  5. joblib — Model persistence
  6. Scikit-learn — Model evaluation (ROC-AUC)
  7. Credit Score Project — Repositório de referência