Hackathon · Machine learning · 2025

ExoLens

Exploração e classificação de exoplanetas, feita em um fim de semana para o NASA Space Apps.

Status
Protótipo
Contexto
Projeto em equipe · NASA Space Apps 2025
Meu papel
Machine learning e API: treinei os modelos, criei a API em FastAPI e fiz o upload de curvas de luz e o gráfico interativo no front-end.
Tecnologias
  • Python
  • scikit-learn
  • XGBoost
  • pandas
  • FastAPI
  • Next.js
  • TypeScript
  • three.js
  • Recharts
Laboratório do ExoLens: formulário com seis parâmetros de exoplaneta ao lado de uma prévia em 3D.
O formulário que envia as seis medidas ao modelo.

Visão geral

Projeto de uma equipe de cinco pessoas, feito no fim de semana do NASA Space Apps Challenge (4 e 5 de outubro de 2025), num desafio sobre usar IA com os dados de exoplanetas da NASA.

Problema

Muitos candidatos a exoplaneta nos catálogos da NASA são falsos positivos. Separar um do outro é um problema clássico de classificação.

Abordagem

Dividimos o trabalho com um contrato simples: seis números entram, uma classificação sai. Assim o front-end avançou em paralelo enquanto eu treinava o modelo.

Como funciona

  1. Dados

    Limpei e juntei as tabelas K2 e TESS e separei seis medidas do planeta e da estrela.

  2. Modelos

    Comparei Random Forest e XGBoost com validação cruzada e pesos por classe, porque havia muito mais planetas confirmados que falsos positivos.

  3. API

    Serviço em FastAPI com predição individual e em lote.

  4. Interface

    Na página de laboratório, fiz o upload de curvas de luz em CSV e o gráfico interativo.

Do catálogo à predição
  • Dados
  • Código
  • IA
  • Resultado
  1. Catálogos da NASA (Dados)K2 e TESS
  2. Preparação (Código)Limpeza e seis medidas
  3. Modelos (IA)Random Forest e XGBoost
  4. API (Código)FastAPI
  5. Interface (Resultado)Next.js, 3D e gráficos
@app.post("/predict", response_model=PredictionResponse)
def predict(features: ExoplanetFeatures):
    if model is None or scaler is None:
        raise HTTPException(status_code=503, detail="Modelos de classificação não carregados")

    # Converter para array na ordem correta
    feature_array = np.array([[
        features.pl_orbper,
        features.pl_rade,
        features.pl_trandep,
        features.st_teff,
        features.st_rad,
        features.st_logg
    ]])

    feature_scaled = scaler.transform(feature_array)
    prediction = model.predict(feature_scaled)[0]
    probabilities = model.predict_proba(feature_scaled)[0]
Trecho do repositório público (back-ia/api/api.py), sem alterações.

Decisões principais

  • Modelo simples, de propósito

    Com poucas horas, modelos de árvore sobre dados de tabela eram a escolha certa, em vez de uma rede neural.

  • Olhar o erro de cada classe

    O teste tinha 127 falsos positivos contra 1.263 planetas confirmados. A acurácia geral escondia os erros da classe menor.

  • Uma API entre o modelo e a interface

    Um contrato pequeno deixou as duas partes independentes até o fim.

Resultado

Protótipo funcionando ao fim do fim de semana, com código público. As capturas são do repositório rodando localmente.

Capturas