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:
- Dados — features numéricas e categóricas, target binário (inadimplente / não)
- Pré-processamento — imputação de missing, encoding de categóricas, escalonamento se necessário
- Modelo — tipicamente Logistic Regression, Random Forest ou XGBoost
- Avaliação — AUC-ROC, AUC-PR, KS, matriz de confusão na classe minoritária
- 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çãoclass_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 oColumnTransformer— 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_resourceapó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.