{ "cells": [ { "cell_type": "markdown", "id": "90710a92", "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": "5e2bab53", "metadata": { "execution": { "iopub.execute_input": "2026-06-07T23:11:56.681238Z", "iopub.status.busy": "2026-06-07T23:11:56.680938Z", "iopub.status.idle": "2026-06-07T23:11:57.169135Z", "shell.execute_reply": "2026-06-07T23:11:57.168256Z" } }, "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", "\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": "01b6d291", "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": "39011534", "metadata": { "execution": { "iopub.execute_input": "2026-06-07T23:11:57.170725Z", "iopub.status.busy": "2026-06-07T23:11:57.170545Z", "iopub.status.idle": "2026-06-07T23:11:57.534804Z", "shell.execute_reply": "2026-06-07T23:11:57.534327Z" } }, "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": "7727e9ca", "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": "1e40e4de", "metadata": { "execution": { "iopub.execute_input": "2026-06-07T23:11:57.536360Z", "iopub.status.busy": "2026-06-07T23:11:57.536237Z", "iopub.status.idle": "2026-06-07T23:11:57.547915Z", "shell.execute_reply": "2026-06-07T23:11:57.547430Z" } }, "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": "7cf32f02", "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": "6ac506ed", "metadata": { "execution": { "iopub.execute_input": "2026-06-07T23:11:57.549463Z", "iopub.status.busy": "2026-06-07T23:11:57.549345Z", "iopub.status.idle": "2026-06-07T23:11:57.812722Z", "shell.execute_reply": "2026-06-07T23:11:57.812187Z" } }, "outputs": [ { "data": { "text/html": [ "
| \n", " | Trecho | \n", "Media_PAX_Diario | \n", "Desvio_Padrao_PAX | \n", "Total_PAX | \n", "Dias_Operados | \n", "
|---|---|---|---|---|---|
| 223 | \n", "SBGL-SBBR | \n", "0.980822 | \n", "4.097998 | \n", "358.0 | \n", "38 | \n", "
| 69 | \n", "SBBR-SBGL | \n", "0.794521 | \n", "3.483710 | \n", "290.0 | \n", "34 | \n", "
| 72 | \n", "SBBR-SBGR | \n", "0.487671 | \n", "2.420831 | \n", "178.0 | \n", "21 | \n", "
| 272 | \n", "SBGR-SBBR | \n", "0.476712 | \n", "2.481277 | \n", "174.0 | \n", "21 | \n", "
| 237 | \n", "SBGL-SBGR | \n", "0.460274 | \n", "2.575601 | \n", "168.0 | \n", "19 | \n", "