{ "cells": [ { "cell_type": "markdown", "id": "07d7e46d", "metadata": {}, "source": [ "# Alocação de Frotas (Fleet Scheduling) - Aeronaves C-97\n", "\n", "Este projeto visa realizar a alocação de frota (Fleet Assignment) baseada nos princípios do livro referenciado *Airline Operations and Scheduling*.\n", "Diferentemente do modelo anterior que utilizava aeronaves de carga, este foca exclusivamente na aeronave de passageiros **C-97**.\n", "\n", "## Objetivos:\n", "1. Remover cálculos de aeronaves de carga.\n", "2. Analisar as demandas diárias para a aeronave C-97.\n", "3. Identificar os esquadrões detentores dessas aeronaves e a quantidade de aeronaves (matrículas únicas).\n", "4. Calcular os 5 trechos mais relevantes do ano de 2025 utilizando estatística e gráficos.\n", "5. Realizar o Fleet Assignment para os 5 trechos, visando minimizar o custo total da operação (Modelo 1 proposto).\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "3f9fa4c6", "metadata": { "execution": { "iopub.execute_input": "2026-06-07T23:37:16.312196Z", "iopub.status.busy": "2026-06-07T23:37:16.311487Z", "iopub.status.idle": "2026-06-07T23:37:16.933888Z", "shell.execute_reply": "2026-06-07T23:37:16.933301Z" } }, "outputs": [], "source": [ "# Importação de bibliotecas\n", "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import seaborn as sns\n", "import pulp\n", "import pymap3d as pm\n", "import math\n", "import networkx as nx\n", "\n", "# Configuração de estilo para os gráficos\n", "sns.set_theme(style=\"whitegrid\")\n", "\n", "# Constantes globais\n", "CSV_FILEPATH = \"SISCO_AEREA_01-01-2025_A_31-12-2025_1911251714Z.csv\"\n", "JSON_AEROPORTOS = \"airports.json\"\n", "CAPACIDADE_C97 = 30 # Capacidade média de passageiros do C-97 (Brasília)\n" ] }, { "cell_type": "markdown", "id": "6054dba5", "metadata": {}, "source": [ "## 1. Leitura e Limpeza dos Dados\n", "Vamos carregar os dados, filtrar apenas para o modelo `C-97` e tratar os campos de localidades e datas.\n" ] }, { "cell_type": "code", "execution_count": 2, "id": "da258d7f", "metadata": { "execution": { "iopub.execute_input": "2026-06-07T23:37:16.935502Z", "iopub.status.busy": "2026-06-07T23:37:16.935296Z", "iopub.status.idle": "2026-06-07T23:37:17.297220Z", "shell.execute_reply": "2026-06-07T23:37:17.296482Z" } }, "outputs": [], "source": [ "# Carregamento do banco de dados\n", "df = pd.read_csv(CSV_FILEPATH, low_memory=False)\n", "df_aeroportos = pd.read_json(JSON_AEROPORTOS, orient='index')\n", "\n", "# Tratamento básico de valores nulos expressos como 'NIL'\n", "df.replace('NIL', 0, inplace=True)\n", "\n", "# Filtro para a aeronave C-97 (Passageiros) e remoção de registros de carga\n", "df_c97 = df[df['Modelo'] == 'C-97'].copy()\n", "\n", "# Filtrando decolagens e pousos conhecidos\n", "df_c97 = df_c97[df_c97['Localidade Decolagem'] != 0]\n", "df_c97 = df_c97[df_c97['Localidade Pouso'] != 0]\n", "\n", "# Criação da coluna Trecho\n", "df_c97['Trecho'] = df_c97['Localidade Decolagem'] + '-' + df_c97['Localidade Pouso']\n", "\n", "# Conversão da coluna PAX para numérico\n", "df_c97['PAX'] = pd.to_numeric(df_c97['PAX']).fillna(0)\n", "\n", "# Tratamento de datas\n", "df_c97['Dep TimeStamp'] = pd.to_datetime(df_c97['Data de Decolagem'] + ' ' + df_c97['Hora de Decolagem'], format='mixed', dayfirst=True)\n", "df_c97['Data Apenas'] = df_c97['Dep TimeStamp'].dt.date\n" ] }, { "cell_type": "markdown", "id": "2424db2d", "metadata": {}, "source": [ "## 2. Análise dos Esquadrões e Matrículas (Aeronaves)\n", "Identificaremos quais esquadrões operam o C-97 e qual a disponibilidade de aeronaves (número de matrículas únicas), pois isso definirá as restrições de frota.\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "8b308e12", "metadata": { "execution": { "iopub.execute_input": "2026-06-07T23:37:17.298752Z", "iopub.status.busy": "2026-06-07T23:37:17.298630Z", "iopub.status.idle": "2026-06-07T23:37:17.310776Z", "shell.execute_reply": "2026-06-07T23:37:17.310206Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Esquadrões que operam o C-97: ETA1, ETA3, ETA5, ETA6, ETA7, ETA2, PAMA SP\n", "Total de matrículas únicas (aeronaves disponíveis): 14\n", "\n", "Aeronaves por esquadrão:\n", " - ETA1: 1 aeronaves\n", " - ETA2: 1 aeronaves\n", " - ETA3: 3 aeronaves\n", " - ETA5: 1 aeronaves\n", " - ETA6: 4 aeronaves\n", " - ETA7: 3 aeronaves\n", " - PAMA SP: 1 aeronaves\n", "\n", "Bases inferidas por esquadrão (pela moda de decolagens):\n", " - ETA1: SBBE\n", " - ETA2: SBNT\n", " - ETA3: SBGL\n", " - ETA5: SBCO\n", " - ETA6: SBBR\n", " - ETA7: SBMN\n", " - PAMA SP: SBGR\n" ] } ], "source": [ "# Obtendo esquadrões e matrículas únicas\n", "esquadroes = df_c97['Emissor'].unique()\n", "matriculas_unicas = df_c97['Matrícula'].unique()\n", "total_aeronaves = len(matriculas_unicas)\n", "\n", "print(f\"Esquadrões que operam o C-97: {', '.join(esquadroes)}\")\n", "print(f\"Total de matrículas únicas (aeronaves disponíveis): {total_aeronaves}\")\n", "\n", "# Aeronaves por esquadrão\n", "aeronaves_por_esquadrao = df_c97.groupby('Emissor')['Matrícula'].nunique().to_dict()\n", "print(\"\\nAeronaves por esquadrão:\")\n", "for esq, qtd in aeronaves_por_esquadrao.items():\n", " print(f\" - {esq}: {qtd} aeronaves\")\n", " \n", "# Identificar a base principal de cada esquadrão (aeroporto com mais decolagens)\n", "bases_esquadroes = {}\n", "for esq in aeronaves_por_esquadrao.keys():\n", " base = df_c97[df_c97['Emissor'] == esq]['Localidade Decolagem'].mode()[0]\n", " bases_esquadroes[esq] = base\n", "\n", "print(\"\\nBases inferidas por esquadrão (pela moda de decolagens):\")\n", "for esq, base in bases_esquadroes.items():\n", " print(f\" - {esq}: {base}\")\n" ] }, { "cell_type": "markdown", "id": "4909bfef", "metadata": {}, "source": [ "## 3. Análise Estatística das Demandas Diárias\n", "Para definir os trechos mais relevantes do ano, calcularemos a demanda de passageiros (PAX) agregada diariamente. Em seguida, extraímos a **média de passageiros diários** e o **desvio padrão** para cada trecho. A relevância será determinada pela maior média de demanda diária de PAX.\n", "Começaremos focando em 5 trechos (alvo variável).\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "b38abd07", "metadata": { "execution": { "iopub.execute_input": "2026-06-07T23:37:17.312196Z", "iopub.status.busy": "2026-06-07T23:37:17.312078Z", "iopub.status.idle": "2026-06-07T23:37:17.621631Z", "shell.execute_reply": "2026-06-07T23:37:17.620923Z" } }, "outputs": [ { "data": { "text/html": [ "
| \n", " | Trecho | \n", "Media_PAX_Diario | \n", "Desvio_Padrao_PAX | \n", "Total_PAX | \n", "Dias_Operados | \n", "Media_PAX_Dias_Operados | \n", "Score_Relevancia | \n", "
|---|---|---|---|---|---|---|---|
| 223 | \n", "SBGL-SBBR | \n", "0.980822 | \n", "4.097998 | \n", "358.0 | \n", "38 | \n", "9.421053 | \n", "13604.0 | \n", "
| 69 | \n", "SBBR-SBGL | \n", "0.794521 | \n", "3.483710 | \n", "290.0 | \n", "34 | \n", "8.529412 | \n", "9860.0 | \n", "
| 72 | \n", "SBBR-SBGR | \n", "0.487671 | \n", "2.420831 | \n", "178.0 | \n", "21 | \n", "8.476190 | \n", "3738.0 | \n", "
| 272 | \n", "SBGR-SBBR | \n", "0.476712 | \n", "2.481277 | \n", "174.0 | \n", "21 | \n", "8.285714 | \n", "3654.0 | \n", "
| 237 | \n", "SBGL-SBGR | \n", "0.460274 | \n", "2.575601 | \n", "168.0 | \n", "19 | \n", "8.842105 | \n", "3192.0 | \n", "
| 437 | \n", "SBSJ-SBBR | \n", "0.339726 | \n", "2.016330 | \n", "124.0 | \n", "18 | \n", "6.888889 | \n", "2232.0 | \n", "
| 277 | \n", "SBGR-SBGL | \n", "0.353425 | \n", "1.885025 | \n", "129.0 | \n", "17 | \n", "7.588235 | \n", "2193.0 | \n", "
| 441 | \n", "SBSJ-SBGL | \n", "0.284932 | \n", "1.705169 | \n", "104.0 | \n", "19 | \n", "5.473684 | \n", "1976.0 | \n", "
| 253 | \n", "SBGL-SBSJ | \n", "0.263014 | \n", "1.619550 | \n", "96.0 | \n", "20 | \n", "4.800000 | \n", "1920.0 | \n", "
| 53 | \n", "SBBR-SBAN | \n", "0.336986 | \n", "2.304767 | \n", "123.0 | \n", "13 | \n", "9.461538 | \n", "1599.0 | \n", "