Biblioteca de predicciones perezosas | Predicción de precios de vuelos mediante predicción diferida

Contenidos

Este artículo fue publicado como parte del Blogatón de ciencia de datos

1. Objetivo

El objetivo de este artículo es predecir los precios de los vuelos dados los distintos parámetros. Los datos utilizados en este artículo están disponibles públicamente en Kaggle. Este será un problema de regresión ya que la variable objetivo o dependiente es el precio (valor numérico continuo).

2. Introducción

Las compañías aéreas utilizan algoritmos complejos para calcular los precios de los vuelos dadas las diversas condiciones presentes en ese momento en particular. Estos métodos tienen en cuenta factores financieros, de marketing y sociales para predecir los precios de los vuelos.

Hoy en día, el número de personas que utilizan vuelos ha aumentado significativamente. Es difícil para las aerolíneas mantener los precios, ya que los precios cambian dinámicamente debido a diferentes condiciones. Es por eso que intentaremos utilizar el aprendizaje automático para resolver este problema. Esto puede ayudar a las aerolíneas al predecir qué precios pueden mantener. También puede ayudar a los clientes a predecir los precios futuros de los vuelos y planificar su viaje en consecuencia.

3. Datos utilizados

Se utilizaron datos de Kaggle, que es una plataforma de acceso gratuito para científicos de datos y entusiastas del aprendizaje automático.

Fuente: https://www.kaggle.com/nikhilmittal/flight-fare-prediction-mh

Estamos usando jupyter-notebook para ejecutar la tarea de predicción de precios de vuelo.

4. Análisis de datos

El procedimiento de extraer información de datos brutos dados se llama análisis de datos. Aquí usaremos eda módulo de preparación de datos biblioteca para hacer este paso.

from dataprep.eda import create_report
import pandas as pd
dataframe = pd.read_excel("../output/Data_Train.xlsx")
create_report(dataframe)

Descripción general de Lazy Prediction

Después de ejecutar el código anterior, obtendrá un informe como se muestra en la figura anterior. Este informe contiene varias secciones o pestañas. La sección ‘Descripción general’ de este informe nos proporciona toda la información básica de los datos que estamos utilizando. Para los datos actuales que estamos usando, obtuvimos la siguiente información:

Número de variables = 11
Número de filas = 10683
Número de tipo categórico de característica = 10
Número de tipo numérico de característica = 1
Filas nuplicadas = 220, etc.

Exploremos otras secciones del informe una por una.

4.1 Variables

Después de seleccionar la sección de variables, obtendrá información como se muestra en las siguientes figuras.

Variables de predicción perezosa

Variables de predicción perezosa 2

Variables de predicción perezosa 2

Esta sección proporciona el tipo de cada variable junto con una descripción detallada de la variable.

4.2 Valores perdidos

Esta sección tiene varias formas en las que podemos analizar los valores perdidos en las variables. Discutiremos tres métodos más utilizados, gráfico de barras, espectro y mapa de calor. Exploremos cada uno por uno.

4.2.1 Gráfico de barras

Gráfico de barras de predicción perezosa

El método de gráfico de barras muestra el ‘número de valores perdidos y presentes’ en cada variable en un color diferente.

4.2.2 Espectro

Espectro de predicción perezosa

El método del espectro muestra el porcentaje de valores perdidos en cada variable.

4.2.3 Mapa de calor

Predicción perezosa del mapa de calor

El método del mapa de calor muestra las variables que tienen valores perdidos en términos de correlación. Dado que ‘Ruta’ y ‘Total_Paradas’ están altamente correlacionados, ambos tienen valores perdidos.

Como podemos observar, las variables ‘Ruta’ y ‘Total_Paradas’ tienen valores perdidos. Dado que no encontramos ninguna información de valores faltantes del método de gráfico de barras y espectro, pero encontramos variables de valores faltantes utilizando el método del mapa de calor. Combinando esta información, podemos decir que las variables ‘Ruta’ y ‘Total_Paradas’ tienen valores perdidos pero son muy bajos.

5. Preparación de datos

Antes de comenzar la preparación de datos, primero echemos un vistazo a los datos.

dataframe.head()

Cabeza de predicción perezosa

Como vimos en Análisis de datos, hay 11 variables en los datos dados. A continuación se muestra la descripción de cada variable.

Aerolínea: Nombre de la aerolínea utilizada para viajar

Date_of_Journey: Fecha en la que viajó una persona

Fuente: Lugar de inicio del vuelo

Destino: Lugar de finalización del vuelo

Ruta: Contiene información sobre la ubicación de inicio y finalización del viaje en el formato estándar utilizado por las aerolíneas.

Dep_Time: Hora de salida del vuelo desde el lugar de inicio

Hora de llegada: Hora de llegada del vuelo al destino

Duración: Duración del vuelo en horas / minutos

Paradas_total: Número total de escalas que realizó el vuelo antes de aterrizar en el destino.

Información adicional: Muestra cualquier información adicional sobre un vuelo

Precio: Precio del vuelo

Pocas observaciones sobre algunas de las variables:

1. ‘Precio‘será nuestra variable dependiente y todas las variables restantes se pueden utilizar como variables independientes.

2. ‘Total_Paradas‘se puede utilizar para determinar si el vuelo fue directo o con conexión.

5.1 Manejo de valores perdidos

Como descubrimos, las variables ‘Ruta’ y ‘Total_Paradas’ tienen valores perdidos muy bajos en los datos. Veamos ahora el porcentaje de valores perdidos en los datos.

(dataframe.isnull().sum()/dataframe.shape[0])*100

Producción :

Airline            0.000000
Date_of_Journey    0.000000
Source             0.000000
Destination        0.000000
Route              0.009361
Dep_Time           0.000000
Arrival_Time       0.000000
Duration           0.000000
Total_Stops        0.009361
Additional_Info    0.000000
Price              0.000000
dtype: float64

Como podemos observar, ‘Route’ y ‘Total_Stops’ tienen ambos 0.0094% de valores perdidos. En este caso, es mejor eliminar los valores perdidos.

dataframe.dropna(inplace= True)
dataframe.isnull().sum()

Producción :

Airline            0
Date_of_Journey    0
Source             0
Destination        0
Route              0
Dep_Time           0
Arrival_Time       0
Duration           0
Total_Stops        0
Additional_Info    0
Price              0
dtype: int64

Ahora no tenemos ningún valor perdido.

5.2 Manejo de variables de fecha y hora

Tenemos ‘Date_of_Journey’, una ‘variable de tipo de fecha y’ Dep_Time ‘,’ Arrival_Time ‘que captura información de tiempo.

Podemos extraer ‘Journey_day’ y ‘Journey_Month’ de la variable ‘Date_of_Journey’. «Día del viaje» muestra el día del mes en el que se inició el viaje.

dataframe["Journey_day"] = pd.to_datetime(dataframe.Date_of_Journey, format="%d/%m/%Y").dt.day
dataframe["Journey_month"] = pd.to_datetime(dataframe["Date_of_Journey"], format = "%d/%m/%Y").dt.month
dataframe.drop(["Date_of_Journey"], axis = 1, inplace = True)

De manera similar, podemos extraer ‘Hora de salida’ y ‘Hora de salida’ así como ‘Hora de llegada y Minuto de llegada’ de las variables ‘Hora_dep.’ Y ‘Hora de llegada’ respectivamente.

dataframe["Dep_hour"] = pd.to_datetime(dataframe["Dep_Time"]).dt.hour
dataframe["Dep_min"] = pd.to_datetime(dataframe["Dep_Time"]).dt.minute
dataframe.drop(["Dep_Time"], axis = 1, inplace = True)
dataframe["Arrival_hour"] = pd.to_datetime(dataframe.Arrival_Time).dt.hour
dataframe["Arrival_min"] = pd.to_datetime(dataframe.Arrival_Time).dt.minute
dataframe.drop(["Arrival_Time"], axis = 1, inplace = True)

También tenemos información sobre la duración de la variable ‘Duración’. Esta variable contiene información combinada de horas y minutos de duración.

Podemos extraer ‘Duración_horas’ y ‘Duración_minutos’ por separado de la variable ‘Duración’.

def get_duration(x):
    x=x.split(' ')
    hours=0
    mins=0
    if len(x)==1:
        x=x[0]
        if x[-1]=='h':
            hours=int(x[:-1])
        else:
            mins=int(x[:-1])
    else:
        hours=int(x[0][:-1])
        mins=int(x[1][:-1])
    return hours,mins
dataframe['Duration_hours']=dataframe.Duration.apply(lambda x:get_duration(x)[0])
dataframe['Duration_mins']=dataframe.Duration.apply(lambda x:get_duration(x)[1])
dataframe.drop(["Duration"], axis = 1, inplace = True)

5.3 Manejo de datos categóricos

Aerolínea, Origen, Destino, Ruta, Total_Paradas, Información adicional son las variables categóricas que tenemos en nuestros datos. Manejemos cada uno por uno.

Variable de aerolínea

Veamos cómo se relaciona la variable Aerolínea con la variable Precio.

import seaborn as sns
sns.set()
sns.catplot(y = "Price", x = "Airline", data = train_data.sort_values("Price", ascending = False), kind="boxen", height = 6, aspect = 3)
plt.show()
49742airline_vs_price-6161207

Como podemos ver, el nombre de la aerolínea importa. ‘JetAirways Business’ tiene el rango de precios más alto. El precio de otras aerolíneas también varía.

Desde el Aerolínea variable es Datos categóricos nominales (No hay orden de ningún tipo en los nombres de las aerolíneas) usaremos codificación one-hot para manejar esta variable.

Airline = dataframe[["Airline"]]
Airline = pd.get_dummies(Airline, drop_first= True)

Los datos de ‘Aerolínea’ codificados en One-Hot se guardan en la variable Aerolínea como se muestra en el código anterior.

Variable de origen y destino

Nuevamente, las variables de ‘Fuente’ y ‘Destino’ son datos categóricos nominales. Usaremos la codificación One-Hot nuevamente para manejar estas dos variables.

Source = dataframe[["Source"]]
Source = pd.get_dummies(Source, drop_first= True)
Destination = train_data[["Destination"]]
Destination = pd.get_dummies(Destination, drop_first = True)

Variable de ruta

La variable de ruta representa la ruta del viaje. Dado que la variable ‘Total_Stops’ captura la información si el vuelo es directo o conectado, he decidido eliminar esta variable.

dataframe.drop(["Route", "Additional_Info"], axis = 1, inplace = True)

Total_Paradas Variable

dataframe["Total_Stops"].unique()

Producción:

array(['non-stop', '2 stops', '1 stop', '3 stops', '4 stops'],
      dtype=object)

Aquí, sin escalas significa 0 escalas, lo que significa vuelo directo. De manera similar, el significado de otros valores es obvio. Podemos ver que es un Datos categóricos ordinales entonces usaremos LabelEncoder aquí para manejar esta variable.

dataframe.replace({"non-stop": 0, "1 stop": 1, "2 stops": 2, "3 stops": 3, "4 stops": 4}, inplace = True)

Variable Additional_Info

dataframe.Additional_Info.unique()

Producción:

array(['No info', 'In-flight meal not included',
       'No check-in baggage included', '1 Short layover', 'No Info',
       '1 Long layover', 'Change airports', 'Business class',
       'Red-eye flight', '2 Long layover'], dtype=object)

Como podemos ver, esta característica captura información relevante que puede afectar el precio del vuelo de manera significativa. También se repiten los valores ‘Sin información’. Manejemos eso primero.

dataframe['Additional_Info'].replace({"No info": 'No Info'}, inplace = True)

Ahora bien, esta variable también es Datos categóricos nominales. Usemos One-Hot Encoding para manejar esta variable.

Add_info = dataframe[["Additional_Info"]]
Add_info = pd.get_dummies(Add_info, drop_first = True)

5.4 Marco de datos final

Ahora crearemos el marco de datos final concatenando todas las características codificadas por etiquetas y One-hot en el marco de datos original. También eliminaremos las variables originales con las que hemos preparado nuevas variables codificadas.

dataframe = pd.concat([dataframe, Airline, Source, Destination,Add_info], axis = 1)
dataframe.drop(["Airline", "Source", "Destination","Additional_Info"], axis = 1, inplace = True)

Veamos el número de variables finales que tenemos en el marco de datos.

dataframe.shape[1]

Producción:

38

Entonces, tenemos 38 variables en el marco de datos final, incluida la variable dependiente ‘Precio’. Solo hay 37 variables para el entrenamiento.

6. Construcción de modelos

X=dataframe.drop('Price',axis=1)
y=dataframe['Price']
#train-test split
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, random_state = 42)

6.1 Aplicación de la predicción perezosa

Uno de los problemas del ejercicio de creación de modelos es «¿Cómo decidir qué algoritmo de aprendizaje automático aplicar?»

Aquí es donde entra en juego Lazy Prediction. Lazy Prediction es una biblioteca de aprendizaje automático disponible en Python que puede proporcionarnos rápidamente el rendimiento de múltiples clasificaciones estándar o modelos de regresión en múltiples matrices de rendimiento.

Vamos a ver cómo funciona…

Como estamos trabajando en una tarea de Regresión, usaremos modelos Regresores.

from lazypredict.Supervised import LazyRegressor
reg = LazyRegressor(verbose=0, ignore_warnings=False, custom_metric=None)
models, predictions = reg.fit(x_train, x_test, y_train, y_test)
models.head(10)
59596screenshot20from202021-06-182012-50-25-2129186

Como podemos ver, LazyPredict nos da resultados de múltiples modelos en múltiples matrices de desempeño. En la figura anterior, hemos mostrado los diez mejores modelos.

Aquí ‘XGBRegressor’ y ‘ExtraTreesRegressor’ superan significativamente a otros modelos. Se necesita una gran cantidad de tiempo de entrenamiento con respecto a otros modelos. En este paso podemos elegir la prioridad si queremos «tiempo» o «rendimiento».

Hemos decidido elegir «rendimiento» sobre el tiempo de entrenamiento. Así que entrenaremos a ‘XGBRegressor y visualizaremos los resultados finales.

6.2 Entrenamiento de modelos

from xgboost import XGBRegressor
model =  XGBRegressor()
model.fit(x_train,y_train)

Producción:

XGBRegressor(base_score=0.5, booster="gbtree", colsample_bylevel=1,
             colsample_bynode=1, colsample_bytree=1, gamma=0, gpu_id=-1,
             importance_type="gain", interaction_constraints="",
             learning_rate=0.300000012, max_delta_step=0, max_depth=6,
             min_child_weight=1, missing=nan, monotone_constraints="()",
             n_estimators=100, n_jobs=0, num_parallel_tree=1, random_state=0,
             reg_alpha=0, reg_lambda=1, scale_pos_weight=1, subsample=1,
             tree_method='exact', validate_parameters=1, verbosity=None)

Comprobemos el rendimiento del modelo …

y_pred =  model.predict(x_test)
print('Training Score :',model.score(x_train, y_train))
print('Test Score     :',model.score(x_test, y_test))

Producción:

Training Score : 0.9680428701701702
Test Score     : 0.918818721300552

Como podemos ver, la puntuación del modelo es bastante buena. Visualicemos los resultados de algunas predicciones.

number_of_observations=50

x_ax = range(len(y_test[:number_of_observations]))

plt.plot(x_ax, y_test[:number_of_observations], label="original")

plt.plot(x_ax, y_pred[:number_of_observations], label="predicted")

plt.title("Flight Price test and predicted data")

plt.xlabel('Observation Number')

plt.ylabel('Price')

plt.legend()

plt.show()
48550test_and_predicted_data-3151743

Como podemos observar en la figura anterior, las predicciones del modelo y los precios originales se superponen. Este resultado visual confirma la alta puntuación del modelo que vimos anteriormente.

7. Conclusión

En este artículo, vimos cómo aplicar la biblioteca Laze Prediction para elegir el mejor algoritmo de aprendizaje automático para la tarea en cuestión.

Lazy Prediction ahorra tiempo y esfuerzos para crear un modelo de aprendizaje automático al proporcionar rendimiento del modelo y tiempo de capacitación. Uno puede elegir cualquiera según la situación en cuestión.

También se puede utilizar para crear un conjunto de modelos de aprendizaje automático. Hay muchas formas en las que se pueden utilizar las funcionalidades de la biblioteca LazyPredict.

Espero que este artículo le haya ayudado a comprender los enfoques de análisis de datos, preparación de datos y creación de modelos de una manera mucho más sencilla.

Comuníquese con la sección de comentarios en caso de cualquier consulta.

Gracias y que tenga un buen día. 🙂

Los medios que se muestran en este artículo no son propiedad de DataPeaker y se utilizan a discreción del autor.

Suscribite a nuestro Newsletter

No te enviaremos correo SPAM. Lo odiamos tanto como tú.