Skip to content

Explicação da aplicação de uma rede neural perceptron multi camadas na previsão de atrasos de chegadas de voos partindo o Brasil

Notifications You must be signed in to change notification settings

alsgil13/MLP-Flight-Pred

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 

Repository files navigation

Estudos Sobre Atrasos de Voos no Brasil

Uma tentativa de predição de atrasos em chegadas de voos usando MultiLayer Perceptron

Muitas das transformações dos dados utilizadas neste notebook foram aprendidas neste kernel

1. Importando as Bibliotecas que utilizaremos no projeto

import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import classification_report,confusion_matrix

2. Importando DataSet disponível no Kaggle

Para os exemplos seguintes funcionarem você deve baixar o detaset no link acima e salvar na mesma pasta do projeto com o nome de: BrFlights2.csv

df = pd.read_csv('BrFlights2.csv', encoding='latin1')

3. Normalizando e traduzindo nomes das colunas e criando tabela para checagem dos tipos de variáveis

df.columns = ['Flights', 'Airline', 'Flight_Type','Departure_Estimate','Departure_Real','Arrival_Estimate','Arrival_Real','Flight_Situation','Code_Justification','Origin_Airport','Origin_City','Origin_State','Origin_Country','Destination_Airport','Destination_City','Destination_State','Destination_Country','Destination_Long','Destination_Lat','Origin_Long','Origin_Lat']
tab_info=pd.DataFrame(df.dtypes).T.rename(index={0:'column type'})
tab_info=tab_info.append(pd.DataFrame(df.isnull().sum()).T.rename(index={0:'null values'}))
tab_info=tab_info.append(pd.DataFrame(df.isnull().sum()/df.shape[0]*100).T.
                         rename(index={0:'null values (%)'}))
tab_info
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
Flights Airline Flight_Type Departure_Estimate Departure_Real Arrival_Estimate Arrival_Real Flight_Situation Code_Justification Origin_Airport ... Origin_State Origin_Country Destination_Airport Destination_City Destination_State Destination_Country Destination_Long Destination_Lat Origin_Long Origin_Lat
column type object object object object object object object object object object ... object object object object object object float64 float64 float64 float64
null values 0 0 0 0 289196 0 289196 0 1510212 0 ... 0 0 0 0 0 0 0 0 0 0
null values (%) 0 0 0 0 11.3744 0 11.3744 0 59.3983 0 ... 0 0 0 0 0 0 0 0 0 0

3 rows × 21 columns

...
Constatamos que Departure_Real e Arrival_Real tem cerca de 11% de valores nulos.
Deletaremos esse valores no passo seguinte (Ignorando a coluna Code_Justification e dropando as ,'tuplas' com algum valor nulo)
....

4. Criando um novo DataFrame com colunas calculadas para tratar os dados de Data/Hora

df_time = df[['Flights', 'Airline', 'Flight_Type', 'Departure_Estimate',
       'Departure_Real', 'Arrival_Estimate', 'Arrival_Real',
       'Flight_Situation', 'Origin_Airport',
       'Origin_City', 'Origin_State', 'Origin_Country', 'Destination_Airport',
       'Destination_City', 'Destination_State', 'Destination_Country',
       'Destination_Long', 'Destination_Lat', 'Origin_Long', 'Origin_Lat']]
df_time.dropna(how='any',inplace=True)
df_time['Departure_Estimate'] = pd.to_datetime(df_time['Departure_Estimate'])
df_time['Departure_Real'] = pd.to_datetime(df_time['Departure_Real'])
df_time['Arrival_Estimate'] = pd.to_datetime(df_time['Arrival_Estimate'])
df_time['Arrival_Real'] = pd.to_datetime(df_time['Arrival_Real'])
df_time['Departure_Delays'] =df_time.Departure_Real - df_time.Departure_Estimate
df_time['Arrival_Delays'] = df_time.Arrival_Real - df_time.Arrival_Estimate
df_time['Departure_Delays'] = df_time['Departure_Delays'].apply(lambda x : round(x.total_seconds()/60))
df_time['Arrival_Delays'] = df_time['Arrival_Delays'].apply(lambda x : round(x.total_seconds()/60))

5. Adicionando nossa Classe Objetivo

Estudaremos os atrasos nas Chegadas dos voos

df_time['ArrivalStatus'] = ""
df_time.loc[df_time.Arrival_Delays > 0 , 'ArrivalStatus'] = "Atrasado"
df_time.loc[df_time.Arrival_Delays < 0 , 'ArrivalStatus'] = "Adiantado"
df_time.loc[df_time.Arrival_Delays == 0 , 'ArrivalStatus'] = "Pontual"

6. Visualizando nosso DataFrame cheio de colunas e com a nossa classe :)

df_time.head(10)
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
Flights Airline Flight_Type Departure_Estimate Departure_Real Arrival_Estimate Arrival_Real Flight_Situation Origin_Airport Origin_City ... Destination_City Destination_State Destination_Country Destination_Long Destination_Lat Origin_Long Origin_Lat Departure_Delays Arrival_Delays ArrivalStatus
0 AAL - 203 AMERICAN AIRLINES INC Internacional 2016-01-30 08:58:00+00:00 2016-01-30 08:58:00+00:00 2016-01-30 10:35:00+00:00 2016-01-30 10:35:00+00:00 Realizado Afonso Pena Sao Jose Dos Pinhais ... Porto Alegre RS Brasil -51.175381 -29.993473 -49.172481 -25.532713 0 0 Pontual
1 AAL - 203 AMERICAN AIRLINES INC Internacional 2016-01-13 12:13:00+00:00 2016-01-13 12:13:00+00:00 2016-01-13 21:30:00+00:00 2016-01-13 21:30:00+00:00 Realizado Salgado Filho Porto Alegre ... Miami N/I Estados Unidos -80.287046 25.795865 -51.175381 -29.993473 0 0 Pontual
2 AAL - 203 AMERICAN AIRLINES INC Internacional 2016-01-29 12:13:00+00:00 2016-01-29 12:13:00+00:00 2016-01-29 21:30:00+00:00 2016-01-29 21:30:00+00:00 Realizado Salgado Filho Porto Alegre ... Miami N/I Estados Unidos -80.287046 25.795865 -51.175381 -29.993473 0 0 Pontual
3 AAL - 203 AMERICAN AIRLINES INC Internacional 2016-01-19 12:13:00+00:00 2016-01-18 12:03:00+00:00 2016-01-19 21:30:00+00:00 2016-01-18 20:41:00+00:00 Realizado Salgado Filho Porto Alegre ... Miami N/I Estados Unidos -80.287046 25.795865 -51.175381 -29.993473 -1450 -1489 Adiantado
4 AAL - 203 AMERICAN AIRLINES INC Internacional 2016-01-30 12:13:00+00:00 2016-01-30 12:13:00+00:00 2016-01-30 21:30:00+00:00 2016-01-30 21:30:00+00:00 Realizado Salgado Filho Porto Alegre ... Miami N/I Estados Unidos -80.287046 25.795865 -51.175381 -29.993473 0 0 Pontual
5 AAL - 203 AMERICAN AIRLINES INC Internacional 2016-01-03 23:05:00+00:00 2016-01-03 23:05:00+00:00 2016-01-04 07:50:00+00:00 2016-01-04 07:50:00+00:00 Realizado Miami Miami ... Sao Jose Dos Pinhais PR Brasil -49.172481 -25.532713 -80.287046 25.795865 0 0 Pontual
6 AAL - 203 AMERICAN AIRLINES INC Internacional 2016-01-05 23:05:00+00:00 2016-01-05 23:35:00+00:00 2016-01-06 07:50:00+00:00 2016-01-06 08:35:00+00:00 Realizado Miami Miami ... Sao Jose Dos Pinhais PR Brasil -49.172481 -25.532713 -80.287046 25.795865 30 45 Atrasado
7 AAL - 203 AMERICAN AIRLINES INC Internacional 2016-01-18 12:13:00+00:00 2016-01-18 13:09:00+00:00 2016-01-18 21:30:00+00:00 2016-01-18 22:24:00+00:00 Realizado Salgado Filho Porto Alegre ... Miami N/I Estados Unidos -80.287046 25.795865 -51.175381 -29.993473 56 54 Atrasado
8 AAL - 203 AMERICAN AIRLINES INC Internacional 2016-01-22 23:05:00+00:00 2016-01-22 23:05:00+00:00 2016-01-23 07:50:00+00:00 2016-01-23 07:50:00+00:00 Realizado Miami Miami ... Sao Jose Dos Pinhais PR Brasil -49.172481 -25.532713 -80.287046 25.795865 0 0 Pontual
9 AAL - 203 AMERICAN AIRLINES INC Internacional 2016-01-15 23:05:00+00:00 2016-01-15 23:55:00+00:00 2016-01-16 07:50:00+00:00 2016-01-16 08:28:00+00:00 Realizado Miami Miami ... Sao Jose Dos Pinhais PR Brasil -49.172481 -25.532713 -80.287046 25.795865 50 38 Atrasado

10 rows × 23 columns

Pronto, já temos nosso Dataset importado num dataframe com todas as informações que precisamos... Na verdade veremos futuramente se precisaremos mesmo de todas essas informações...
Seria interessante excluir colunas como Departure_Real e Departure_Delay pois essas informações tornam obvio saber se o voo atrasou ou não... Discutiremos isso mais pra frente
Nosso Próximo Passo agora vai ser extratificar o dataframe em outros dois dataframes um pra treinamento da rede neural e um para validação da nossa rede, cada um destes dataframes vai ser ainda separado em duas Colunas uma com todas as informações e outra somente com a nossa classe (ArrivalStatus)
Extratificar significa que separaremos os dados na proporção que eles tem de valores da nossa classe objetivo, por exemplo, se temos 50% de Voos Pontuais, 40% de atrasos e 10% de adiantamentos os nosso dois dataframes gerados terão essas proporções.

df_time.shape
(2253323, 23)

7. Estratificando nosso dataframe

train, test = train_test_split(df_time, test_size=0.3, stratify=df_time['ArrivalStatus'])
atrasados = train.groupby('ArrivalStatus').get_group('Atrasado').count()[0]
adiantados = train.groupby('ArrivalStatus').get_group('Adiantado').count()[0]
pontuais = train.groupby('ArrivalStatus').get_group('Pontual').count()[0]
total = atrasados + adiantados + pontuais
colunas = ['Situation','%']
train_info = [[atrasados/total*100],[adiantados/total*100],[pontuais/total*100]]


pd.DataFrame(train_info, index=['Atrasados','Adiantados','Pontuais'], columns = ['Percent'])
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
Percent
Atrasados 15.508969
Adiantados 18.276501
Pontuais 66.214530
atrasados = test.groupby('ArrivalStatus').get_group('Atrasado').count()[0]
adiantados = test.groupby('ArrivalStatus').get_group('Adiantado').count()[0]
pontuais = test.groupby('ArrivalStatus').get_group('Pontual').count()[0]
total = atrasados + adiantados + pontuais
colunas = ['Situation','%']
test_info = [[atrasados/total*100],[adiantados/total*100],[pontuais/total*100]]
pd.DataFrame(test_info, index=['Atrasados','Adiantados','Pontuais'], columns = ['Percent'])
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
Percent
Atrasados 15.508945
Adiantados 18.276560
Pontuais 66.214495

Dessa forma temos em ambos os DataFrames aproximadamente 17% de Voos Adiantados, 16% de Voos Atrasados e 68% de Voos Pontuais

8. Separando as perguntas das respostas

train.shape
(1577326, 23)
X_train = train.iloc[:,:22]
Y_train = train.iloc[:,22:]
X_test = test.iloc[:,:22]
Y_test = test.iloc[:,22:]
X_train.shape
(1577326, 22)
Y_train.shape
(1577326, 1)
X_test.shape
(675997, 22)
Y_test.shape
(675997, 1)

O Algoritmo que utilizaremos só aceita variáveis numéricas na origem, dessa forma, o jeito mais fácil, só pra testar o modelo, foi excluir todas,é claro que isso colocou a eficiência da nossa rede lá embaixo... O que precisamos fazer agora é:

  • Definir quais variáveis serão
  • É difícil prever a diferença que cada variável faria, mas podemos começar definindo as mais óbvias como data e cia aérea por exemplo...

  • Transformar as variáveis em conteúdo processável
  • Definidas quais variáveis usaremos devemos ver a melhor técnica para transformá-la em conteúdo que pode ser processado pela RN (ou seja, números)

    Conheco duas, uma é basicamente pegar os caracteres e transformar em números, porém para esta técnica os dados devem possuir algum valor semântico quando transformados em números (funciona para data e hora por exemplo)

    A outra técnica é para dados que não tem valor semântico quando transformados em algarismos (como nomes, por exemplo). Essa técnica é chamada de Dummies, que é bassicamente montar uma tabela onde as colunas teriam os nomes das Cias Aéreas, por exemplo, as linhas seriam os voos e a célula (LinhaXColuna) seria preenchida com 1 se o voo pertence àquela cia aérea e com 0 caso não pertença. Isso impacta diretamente no problema seguinte:

  • Definir a arquitetura da rede
  • Depois de sabermos exatamente o tamanho da nossa entrada (quantas colunas terão nas nossas tabelas X) precisamos definir quantas camadas e quantos neurônios em cada camadas teremos.
    Existem alguns estudos sobre o assunto, mas é um ponto que não é uma unânimidade na área. Podemos tomar como base este artigo

#Mes
#X_Train_mes = pd.DataFrame(X_train[['Departure_Estimate']])
#X_Train_mes['Departure_Estimate'] = X_Train_mes['Departure_Estimate'].dt.month
#look_up = {1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun', 7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec'}
#X_Train_mes['Departure_Estimate'] = X_Train_mes['Departure_Estimate'].apply(lambda x: look_up[x])
#X_Train_mes = pd.get_dummies(X_Train_mes)
#X_Train_mes.head()
#Pegando os valores relevantes
New_X_train = X_train[['Destination_Long', 'Destination_Lat', 'Origin_Long', 'Origin_Lat','Departure_Delays']]
#Transformando Valores relevantes em dados calculáveis
############## Treino
#Linha aérea
Dummies_X_train = X_train[['Airline']]
Dummies_X_train = pd.get_dummies(Dummies_X_train)
#Dia da Semana
X_data = X_train[['Departure_Estimate']]
X_data['Dia_Semana'] = X_data['Departure_Estimate'].dt.weekday_name

#Mes
X_Train_mes = pd.DataFrame(X_train[['Departure_Estimate']])
X_Train_mes['Departure_Estimate'] = X_Train_mes['Departure_Estimate'].dt.month
look_up = {1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun', 7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec'}
X_Train_mes['Departure_Estimate'] = X_Train_mes['Departure_Estimate'].apply(lambda x: look_up[x])
X_Train_mes = pd.get_dummies(X_Train_mes)

#Hora
X_hora = pd.DataFrame(X_data['Departure_Estimate'].dt.hour)
X_data = X_data['Dia_Semana']
X_hora.columns = ['Hora']
X_hora = X_hora['Hora'].apply(str)
X_hora = pd.get_dummies(X_hora)
Dummies_X_Data = pd.get_dummies(X_data)
X_train = pd.concat([New_X_train, Dummies_X_train, Dummies_X_Data, X_hora,X_Train_mes], axis=1)
############## Teste
New_X_test = X_test[['Destination_Long', 'Destination_Lat', 'Origin_Long', 'Origin_Lat','Departure_Delays']]
Dummies_X_test = X_test[['Airline']]
Dummies_X_test = pd.get_dummies(Dummies_X_test)
#Dia da Semana
X_datat = X_test[['Departure_Estimate']]
X_datat['Dia_Semana'] = X_datat['Departure_Estimate'].dt.weekday_name

#Mes
X_test_mes = pd.DataFrame(X_test[['Departure_Estimate']])
X_test_mes['Departure_Estimate'] = X_test_mes['Departure_Estimate'].dt.month
#look_up = {1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun', 7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec'}
X_test_mes['Departure_Estimate'] = X_test_mes['Departure_Estimate'].apply(lambda x: look_up[x])
X_test_mes = pd.get_dummies(X_test_mes)












#Hora
X_horat = pd.DataFrame(X_datat['Departure_Estimate'].dt.hour)

X_datat = X_datat['Dia_Semana']
X_horat.columns = ['Hora']
X_horat = X_horat['Hora'].apply(str)
X_horat = pd.get_dummies(X_horat)
Dummies_X_Datat = pd.get_dummies(X_datat)
X_test = pd.concat([New_X_test, Dummies_X_test, Dummies_X_Datat, X_horat,X_test_mes], axis=1)


X_test_mes.head()
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
Departure_Estimate_Apr Departure_Estimate_Aug Departure_Estimate_Dec Departure_Estimate_Feb Departure_Estimate_Jan Departure_Estimate_Jul Departure_Estimate_Jun Departure_Estimate_Mar Departure_Estimate_May Departure_Estimate_Nov Departure_Estimate_Oct Departure_Estimate_Sep
1687115 0 0 0 0 0 0 0 1 0 0 0 0
1783207 1 0 0 0 0 0 0 0 0 0 0 0
2154287 0 1 0 0 0 0 0 0 0 0 0 0
2074967 0 0 0 0 0 1 0 0 0 0 0 0
535615 0 0 0 0 0 1 0 0 0 0 0 0
#X_test_mes['mes'] = pd.DataFrame(X_datat['Departure_Estimate'].dt.month)
#X_test_mes.head()
#X_test_mes['Departure_Estimate'] = X_test_mes.apply(lambda x: look_up[x])
X_train.shape

(1577326, 103)
X_test.shape
(675997, 103)
X_train.dropna(how='any',inplace=True)
X_train.shape
(1577326, 103)
X_test.dropna(how='any',inplace=True)
X_test.shape
(675997, 103)

9. Vendo como ficou nosso DataFrame aparado

X_train.head()
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
Destination_Long Destination_Lat Origin_Long Origin_Lat Departure_Delays Airline_AEROLINEAS ARGENTINAS Airline_AEROMEXICO Airline_AIR CANADA Airline_AIR CHINA Airline_AIR EUROPA S/A ... Departure_Estimate_Dec Departure_Estimate_Feb Departure_Estimate_Jan Departure_Estimate_Jul Departure_Estimate_Jun Departure_Estimate_Mar Departure_Estimate_May Departure_Estimate_Nov Departure_Estimate_Oct Departure_Estimate_Sep
1584578 -53.700874 -29.707958 -51.175381 -29.993473 46 0 0 0 0 0 ... 0 1 0 0 0 0 0 0 0 0
485150 -56.117269 -15.653079 -47.917235 -15.869737 0 0 0 0 0 0 ... 0 0 0 0 1 0 0 0 0 0
1050608 -48.545966 -27.670118 -46.656584 -23.627325 0 0 0 0 0 0 ... 0 1 0 0 0 0 0 0 0 0
90584 -87.907321 41.974162 -46.478126 -23.434553 0 0 0 0 0 0 ... 0 0 1 0 0 0 0 0 0 0
204307 -47.917235 -15.869737 -51.175381 -29.993473 0 0 0 0 0 0 ... 0 0 0 0 0 1 0 0 0 0

5 rows × 103 columns

X_test.head()
<style scoped> .dataframe tbody tr th:only-of-type { vertical-align: middle; }
.dataframe tbody tr th {
    vertical-align: top;
}

.dataframe thead th {
    text-align: right;
}
</style>
Destination_Long Destination_Lat Origin_Long Origin_Lat Departure_Delays Airline_AEROLINEAS ARGENTINAS Airline_AEROMEXICO Airline_AIR CANADA Airline_AIR CHINA Airline_AIR EUROPA S/A ... Departure_Estimate_Dec Departure_Estimate_Feb Departure_Estimate_Jan Departure_Estimate_Jul Departure_Estimate_Jun Departure_Estimate_Mar Departure_Estimate_May Departure_Estimate_Nov Departure_Estimate_Oct Departure_Estimate_Sep
1687115 -46.656584 -23.627325 -43.965396 -19.634099 0 0 0 0 0 0 ... 0 0 0 0 0 1 0 0 0 0
1783207 -43.249423 -22.813410 -46.656584 -23.627325 0 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0
2154287 -47.917235 -15.869737 -34.950614 -7.147060 31 0 0 0 0 0 ... 0 0 0 0 0 0 0 0 0 0
2074967 -38.331241 -12.911098 -38.533097 -3.777156 0 0 0 0 0 0 ... 0 0 0 1 0 0 0 0 0 0
535615 -57.514181 -25.241513 -46.478126 -23.434553 0 0 0 0 0 0 ... 0 0 0 1 0 0 0 0 0 0

5 rows × 103 columns

Aqui que a IA começa...(pode demorar para processar)

#Definir arquitetura:

mlp = MLPClassifier(activation='relu', alpha=0.0001, batch_size='auto', beta_1=0.9,
       beta_2=0.999, early_stopping=False, epsilon=1e-08,
       hidden_layer_sizes=(9, 7, 5), learning_rate='constant',
       learning_rate_init=0.001, max_iter=200, momentum=0.9,
       nesterovs_momentum=True, power_t=0.5, random_state=None,
       shuffle=True, solver='adam', tol=0.0001, validation_fraction=0.1,
       verbose=False, warm_start=False)
#Magic....
mlp.fit(X_train,Y_train)
#Nostradamus mode on...
predictions = mlp.predict(X_test)
#Plotando nosso resultado...
print(classification_report(Y_test,predictions))
              precision    recall  f1-score   support

   Adiantado       0.93      0.91      0.92    123549
    Atrasado       0.95      0.89      0.92    104840
     Pontual       0.98      1.00      0.99    447608

    accuracy                           0.97    675997
   macro avg       0.95      0.93      0.94    675997
weighted avg       0.97      0.97      0.97    675997

About

Explicação da aplicação de uma rede neural perceptron multi camadas na previsão de atrasos de chegadas de voos partindo o Brasil

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published