Exercício – limpar e preparar os dados

Concluído

Antes de poder preparar um conjunto de dados, precisa de entender o seu conteúdo e estrutura. No laboratório anterior, importou um conjunto de dados que continha informações de chegada à hora definida de uma grande companhia aérea dos Estados Unidos. Estes dados incluíam 26 colunas e milhares de linhas, representando cada linha um voo e contendo informações como o local de partida, o destino e a hora de partida prevista do voo. Também carregou os dados para um bloco de notas do Jupyter e utilizou um script simples do Python para criar um DataFrame do Pandas a partir do mesmo.

Um DataFrame é uma estrutura de dados bidimensional. As colunas num DataFrame podem ser de diferentes tipos, tais como as colunas numa folha de cálculo ou numa tabela de base de dados. É o objeto utilizado com maior frequência no Pandas. Neste exercício, examinará mais a fundo o DataFrame e os dados no interior do mesmo.

  1. Mude novamente para o bloco de notas do Azure que criou na secção anterior. Se você fechou o bloco de anotações, pode entrar novamente no portal de Blocos de Anotações do Microsoft Azure, abrir seu bloco de anotações e usar a célula -Executar tudo para executar novamente todas as células do bloco de anotações depois de abri-lo>.

    The FlightData notebook.

    O bloco de notas FlightData

  2. O código que adicionou ao bloco de notas no laboratório anterior cria um DataFrame a partir do flightdata.csv e chama o DataFrame.head para apresentar as primeiras cinco linhas. Uma das primeiras coisas que geralmente quer saber sobre um conjunto de dados é o número de linhas que contém. Para obter uma contagem, escreva a seguinte instrução numa célula vazia no final do bloco de notas e execute-a:

    df.shape
    

    Confirme que o DataFrame contém 11.231 linhas e 26 colunas:

    Getting a row and column count.

    Obter uma contagem de linhas e colunas

  3. Dedique agora uns momentos a examinar as 26 colunas no conjunto de dados. Estas contêm informações importantes, como a data em que o voo ocorreu (YEAR, MONTH e DAY_OF_MONTH), o local de partida e o destino (ORIGIN e DEST), as horas de partida e de chegada previstas (CRS_DEP_TIME e CRS_ARR_TIME), a diferença entre a hora da chegada prevista e a hora efetiva de chegada em minutos (ARR_DELAY), e se o voo teve um atraso igual ou superior a 15 minutos (ARR_DEL15).

    Segue-se uma lista completa das colunas no conjunto de dados. As horas são expressas no sistema horário de 24 horas. Por exemplo, 1130 é igual a 11h30 e 1500 é igual a 15h00.

    Coluna Description
    YEAR Ano em que ocorreu o voo
    QUARTER Trimestre em que ocorreu o voo (1-4)
    MONTH Mês em que ocorreu o voo (1-12)
    DAY_OF_MONTH Dia do mês em que ocorreu o voo (1-31)
    DAY_OF_WEEK Dia da semana em que ocorreu o voo (1 = Segunda-feira, 2 = Terça-feira, etc.)
    UNIQUE_CARRIER Código da transportadora aérea (por exemplo, DL)
    TAIL_NUM Número de cauda da aeronave
    FL_NUM Número do voo
    ORIGIN_AIRPORT_ID Identificador do aeroporto de partida
    ORIGIN Código do aeroporto de partida (ATL, DFW, SEA, etc.)
    DEST_AIRPORT_ID Identificador do aeroporto de destino
    DEST Código do aeroporto de destino (ATL, DFW, SEA, etc.)
    CRS_DEP_TIME Hora de partida prevista
    DEP_TIME Hora efetiva de partida
    DEP_DELAY Número de minutos em que a partida foi adiada
    DEP_DEL15 0 = Partida com um atraso inferior a 15 minutos, 1 = Partida com um atraso igual ou superior a 15 minutos
    CRS_ARR_TIME Hora da chegada prevista
    ARR_TIME Hora efetiva da chegada
    ARR_DELAY Número de minutos de atraso na chegada do voo
    ARR_DEL15 0 = Chegou com um atraso inferior a 15 minutos, 1 = Chegou com um atraso igual ou superior a 15 minutos
    CANCELLED 0 = O voo não foi cancelado, 1 = O voo foi cancelado
    DIVERTED 0 = O voo não foi desviado, 1 = O voo foi desviado
    CRS_ELAPSED_TIME A duração prevista do voo em minutos
    ACTUAL_ELAPSED_TIME A duração efetiva do voo em minutos
    DISTANCE A distância percorrida em milhas

O conjunto de dados inclui uma distribuição uniforme aproximada das datas ao longo do ano, o que é importante porque um voo que parte de Minneapolis tem menos probabilidade de sofrer um atraso devido a tempestades de inverno em julho do que em janeiro. Mas este conjunto de dados está longe de estar "limpo" e pronto a ser utilizado. Vamos escrever um código do Pandas para o limpar.

Um dos aspetos mais importantes de preparar um conjunto de dados para utilização no machine learning é selecionar as colunas de "funcionalidade" que sejam relevantes para o resultado que está a tentar prever ao filtrar colunas que não afetam o resultado, possam desviá-lo de forma negativa ou produzir multicolinearidade. Outra tarefa importante é eliminar os valores em falta, quer ao eliminar as linhas ou colunas que os contenham, ou ao substituí-los por valores significativos. Neste exercício, irá eliminar colunas irrelevantes e substituir os valores em falta nas restantes colunas.

  1. Uma das primeiras coisas que os cientistas de dados normalmente procuram num conjunto de dados são os valores em falta. Há uma maneira fácil de verificar a existência de valores em falta no Pandas. Para demonstrar, execute o seguinte código numa célula no final do bloco de notas:

    df.isnull().values.any()
    

    Confirme que o resultado é "True", o que indica que existe pelo menos um valor em falta algures no conjunto de dados.

    Checking for missing values.

    Verificar a existência de valores em falta

  2. A próxima etapa é descobrir onde estão os valores em falta. Para tal, execute o seguinte código:

    df.isnull().sum()
    

    Confirme que vê o seguinte resultado a listar uma contagem de valores em falta em cada coluna:

    Number of missing values in each column.

    Número de valores em falta em cada coluna

  3. Curiosamente, a 26ª coluna ("Sem nome: 25") contém 11.231 valores ausentes, o que equivale ao número de linhas no conjunto de dados. Esta coluna foi criada por engano, porque o ficheiro CSV que importou contém uma vírgula no final de cada linha. Para eliminar essa coluna, adicione o seguinte código ao bloco de notas e execute-o:

    df = df.drop('Unnamed: 25', axis=1)
    df.isnull().sum()
    

    Verifique os resultados e confirme que essa coluna 26 desapareceu do DataFrame:

    The DataFrame with column 26 removed.

    O DataFrame com a coluna 26 removida

  4. O DataFrame ainda contém muitos valores em falta, mas alguns deles não são úteis porque as colunas que os contêm não são relevantes para o modelo que está a criar. O objetivo desse modelo é prever se um voo que está a considerar reservar tem probabilidade de chegar à hora prevista. Se souber que o voo tem probabilidade de chegar atrasado, poderá optar por reservar outro voo.

    A próxima etapa é portanto filtrar o conjunto de dados para eliminar as colunas que não são relevantes para um modelo preditivo. Por exemplo, o número de cauda da aeronave tem provavelmente pouca importância no facto de um voo chegar a horas e, no momento de reservar um bilhete, não tem maneira de saber se um voo irá ser cancelado, desviado ou atrasado. Por outro lado, a hora de partida prevista pode ter muito a ver com as chegadas à hora prevista. Devido ao sistema de "hub-and-spoke" utilizado pela maioria das companhias aéreas, os voos da manhã tendem a chegar à hora prevista com mais frequência do que os voos da tarde ou da noite. Além disso, em alguns aeroportos principais, o tráfego intensifica-se durante o dia, aumentando a probabilidade de os voos tardios ficarem atrasados.

    O Pandas fornece uma forma fácil de filtrar as colunas indesejadas. Execute o seguinte código numa nova célula no final do bloco de notas:

    df = df[["MONTH", "DAY_OF_MONTH", "DAY_OF_WEEK", "ORIGIN", "DEST", "CRS_DEP_TIME", "ARR_DEL15"]]
    df.isnull().sum()
    

    O resultado mostra que o DataFrame agora inclui apenas as colunas que são relevantes para o modelo e que o número de valores em falta reduziu bastante:

    The filtered DataFrame.

    O DataFrame filtrado

  5. A única coluna que contém agora valores em falta é a coluna ARR_DEL15, que utiliza o algarismo 0 para identificar os voos que chegaram a horas e 1 para os voos que não chegaram a horas. Utilize o seguinte código para mostrar as primeiras cinco linhas com valores em falta:

    df[df.isnull().values.any(axis=1)].head()
    

    O Pandas representa os valores em falta com NaN, que significa Não é um número. O resultado mostra que estas linhas constituem, de facto, valores em falta na coluna ARR_DEL15:

    Rows with missing values.

    Linhas com valores em falta

  6. O motivo pelo qual estas linhas constituem valores em falta da ARR_DEL15 prende-se com o facto de todas elas corresponderem a voos cancelados ou desviados. Poderia ativar dropna no DataFrame para remover estas linhas. No entanto, dado que um voo que tenha sido cancelado ou desviado para outro aeroporto poderia ser considerado "atrasado", vamos utilizar o método fillna para substituir os valores em falta pelo algarismo 1.

    Utilize o seguinte código para substituir os valores em falta na coluna ARR_DEL15 pelo algarismo 1 e apresentar as linhas 177 a 184:

    df = df.fillna({'ARR_DEL15': 1})
    df.iloc[177:185]
    

    Confirme que os NaN nas linhas 177, 179 e 184 foram substituídos pelo algarismo 1, que indica que os voos chegaram atrasados:

    NaNs replaced with 1s.

    NaN substituídos pelo algarismo 1

O conjunto de dados está agora "limpo", no sentido em que foram substituídos os valores em falta e a lista de colunas foi reduzida para mostrar apenas as mais relevantes para o modelo. Contudo, ainda não terminou. Há mais a fazer para preparar o conjunto de dados para utilização no machine learning.

A coluna CRS_DEP_TIME do conjunto de dados que está a utilizar representa as horas de partida previstas. A granularidade dos números existentes nesta coluna (contém mais de 500 valores exclusivos) poderia ter um impacto negativo na precisão de um modelo de machine learning. Isso pode ser resolvido através de uma técnica chamada discretização ou quantização. E se dividisse cada número nesta coluna por 100 e o arredondasse para o número inteiro mais próximo? 1030 seria 10, 1925 seria 19 e assim por diante, e ficaria com um máximo de 24 valores discretos nesta coluna. Intuitivamente, faz sentido, porque provavelmente não importa muito se um voo parte às 10h30 ou às 10h40. Importa muito se sai às 10h30 ou às 17h30.

Além disso, as colunas do conjunto de dados ORIGIN e DEST contêm códigos do aeroporto que representam valores categóricos de machine learning. Estas colunas precisam de ser convertidas em colunas discretas que contenham variáveis de indicadores, por vezes conhecidas como variáveis fictícias, ou "dummy". Em outras palavras, a coluna ORIGIN, que contém cinco códigos do aeroporto, precisa de ser convertida em cinco colunas, uma por aeroporto, com cada coluna a conter os algarismos 1 e 0 para indicar se o voo partiu do aeroporto representado pela coluna. A coluna DEST deve ser tratada de maneira semelhante.

Neste exercício, irá "discretizar" as horas de partida na coluna CRS_DEP_TIME e utilizar o método get_dummies do Pandas para criar colunas de indicadores a partir das colunas ORIGIN e DEST.

  1. Utilize o seguinte comando para apresentar as primeiras cinco linhas do DataFrame:

    df.head()
    

    Observe que a coluna CRS_DEP_TIME contém valores de 0 a 2359, a representar o sistema horário de 24 horas.

    The DataFrame with unbinned departure times.

    O DataFrame com horas de partida não discretizadas

  2. Utilize as seguintes instruções para discretizar as horas de partida:

    import math
    
    for index, row in df.iterrows():
        df.loc[index, 'CRS_DEP_TIME'] = math.floor(row['CRS_DEP_TIME'] / 100)
    df.head()
    

    Confirme que os números na coluna CRS_DEP_TIME se encontram agora no intervalo de 0 a 23:

    The DataFrame with binned departure times.

    O DataFrame com horas de partida discretizadas

  3. Agora, utilize as seguintes instruções para gerar colunas de indicadores a partir das colunas ORIGIN e DEST, ao remover as próprias colunas ORIGIN e DEST:

    df = pd.get_dummies(df, columns=['ORIGIN', 'DEST'])
    df.head()
    

    Examine o DataFrame resultante e observe que as colunas ORIGIN e DEST foram substituídas por colunas correspondentes aos códigos de aeroporto presentes nas colunas originais. As novas colunas têm os algarismos 1 e 0 a indicar se um determinado voo partiu ou tinha como destino o aeroporto correspondente.

    The DataFrame with indicator columns.

    O DataFrame com colunas de indicadores

  4. Use o comando Arquivo ->Salvar e Ponto de verificação para salvar o bloco de anotações.

O conjunto de dados tem um aspeto muito diferente do que de início, mas foi agora otimizado para utilização no machine learning.