Итак, ребята, вот еще один из моих самых любимых проектов. В этом блоге мы будем внедрять модель прогнозирования цен на авиабилеты с использованием различных методов, а также будем выполнять очень частую визуализацию данных, чтобы лучше понять наши данные. Это будет большой блог, поэтому, не вдаваясь в подробности, выпейте кофе и начните.

Полную статью с исходным кодом читайте здесь —https://machinelearningprojects.net/flight-price-prediction/

Посмотреть видео можно здесь — https://youtu.be/LFQ2JwEVf6M

Давай сделаем это…

Шаг 1 — Импорт библиотек, необходимых для прогнозирования цен на рейсы.

import pandas as pd
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
import datetime as dt
from sklearn.model_selection import train_test_split, RandomizedSearchCV
from sklearn.ensemble import RandomForestRegressor, ExtraTreesRegressor
import pickle

Шаг 2 — Чтение обучающих данных.

train_data = pd.read_excel('Flight Dataset/Data_Train.xlsx')
train_data.head()

Шаг 3 — Проверка значений в столбце «Назначение».

train_data[‘Destination’].value_counts()
  • В нашем наборе данных максимальное количество людей направляется в Кочин, затем в Бангалор, а затем в Дели.

Шаг 3.5 — Слияние Дели и Нью-Дели.

def newd(x):
    if x=='New Delhi':
        return 'Delhi'
    else:
        return x

train_data['Destination'] = train_data['Destination'].apply(newd)
  • Как мы видели выше, у нашего пункта назначения были Дели и Нью-Дели, поэтому мы объединили их оба.

Шаг 4 — Проверка информации о наших данных поезда.

train_data.info()
  • Мы видим, что остановки Route и Total имеют значения 1 1 NULL каждая.
  • Поэтому мы будем отбрасывать значения NULL дальше.

Шаг 5 — Преобразование столбцов дня и месяца в столбцы даты и времени.

train_data['Journey_day'] = pd.to_datetime(train_data['Date_of_Journey'],format='%d/%m/%Y').dt.day
train_data['Journey_month'] = pd.to_datetime(train_data['Date_of_Journey'],format='%d/%m/%Y').dt.month

train_data.drop('Date_of_Journey',inplace=True,axis=1)

train_data.head()
  • Мы извлечем день поездки и месяц поездки из даты поездки и создадим для них 2 столбца, как показано ниже.
  • А затем мы опустим столбец «Дата поездки».

Шаг 6 — Извлечение часов и минут из времени.

train_data['Dep_hour'] = pd.to_datetime(train_data['Dep_Time']).dt.hour
train_data['Dep_min'] = pd.to_datetime(train_data['Dep_Time']).dt.minute
train_data.drop('Dep_Time',axis=1,inplace=True)

train_data['Arrival_hour'] = pd.to_datetime(train_data['Arrival_Time']).dt.hour
train_data['Arrival_min'] = pd.to_datetime(train_data['Arrival_Time']).dt.minute
train_data.drop('Arrival_Time',axis=1,inplace=True)

train_data.head()
  • Как и выше, мы будем извлекать время отправления и минуты отправления из времени отправления.
  • И то же самое будет сделано для времени прибытия.
  • И после этого мы опустим оба столбца.

Шаг 7 — Проверка значений в столбце «Длительность».

train_data[‘Duration’].value_counts()
  • Это продолжительность полетов.
  • 550 полетов продолжительностью 2 часа 50 минут и так далее.

Шаг 8 — Удаление столбца «Длительность» и извлечение из него важной информации.

duration = list(train_data['Duration'])

for i in range(len(duration)):
    if len(duration[i].split()) != 2:
        if 'h' in duration[i]:
            duration[i] = duration[i] + ' 0m'
        else:
            duration[i] = '0h ' + duration[i]

duration_hour = []
duration_min = []

for i in duration:
    h,m = i.split()
    duration_hour.append(int(h[:-1]))
    duration_min.append(int(m[:-1]))

train_data['Duration_hours'] = duration_hour
train_data['Duration_mins'] = duration_min

train_data.drop('Duration',axis=1,inplace=True)
train_data.head()

Строка 1 — Создание списка всех длительностей, присутствующих в данных.

  • Строка 3–8 — мы просто приводим все длительности к одному и тому же формату. Может быть случай, когда некоторая продолжительность полета будет составлять всего 30 м, поэтому мы запишем это как «0 ч 30 м», а также могут быть случаи, такие как 2 ч, поэтому мы запишем это как «2 ч 0 м».
  • Строка 13–16 — просто разделите ее на 2 компонента: часы и минуты.
  • Строка 18–19. Добавьте два столбца «Duration_hours» и «Duration_mins».
  • Строка 21. Удалите исходный столбец «Длительность».

Шаг 9 — График зависимости авиакомпании от цены.

sns.catplot(x=’Airline’,y=’Price’,data=train_data.sort_values(‘Price’,ascending=False),kind=’boxen’,aspect=3,height=6)
  • Из приведенного ниже графика мы можем сделать вывод, что бизнес Jet Airways является самым дорогостоящим авиаперевозчиком.

Шаг 10 — Создание фиктивных столбцов из столбца «Авиакомпания».

airline = train_data[['Airline']]
airline = pd.get_dummies(airline,drop_first=True)
  • Поскольку авиакомпания является категориальным столбцом, мы сделаем из него фиктивные столбцы.

Шаг 11 — Построение графика зависимости источника от цены.

# If we are going from Banglore the prices are slightly higher as compared to other cities
sns.catplot(x='Source',y='Price',data=train_data.sort_values('Price',ascending=False),kind='boxen',aspect=3,height=4)
  • Сюжет ниже говорит о том, что если вы едете из Бангалора, то куда бы вы ни отправились, вам придется заплатить наибольшую сумму денег.

Шаг 12 — Создание фиктивных столбцов из исходного столбца.

source = train_data[['Source']]
source = pd.get_dummies(source,drop_first=True)
source.head()
  • Поскольку Source является категориальным столбцом, мы сделаем из него фиктивные столбцы.

Шаг 13 — Построение графика зависимости от цены.

# If we are going to New Delhi the prices are slightly higher as compared to other cities
sns.catplot(x='Destination',y='Price',data=train_data.sort_values('Price',ascending=False),kind='boxen',aspect=3,height=4)
  • Сюжет ниже говорит о том, что если вы едете в Нью-Дели, неважно откуда, вам придется заплатить самую большую сумму денег.

Шаг 14 — Создание фиктивных столбцов из столбца «Назначение».

destination = train_data[['Destination']]
destination = pd.get_dummies(destination,drop_first=True)
destination.head()
  • Поскольку Destination также является категориальным столбцом, мы сделаем из него фиктивные столбцы.

Шаг 15 — Удаление ненужных столбцов.

train_data.drop([‘Route’,’Additional_Info’],inplace=True,axis=1)

Шаг 16 — Проверка значений в столбце Всего остановок.

train_data[‘Total_Stops’].value_counts()

Шаг 17 — Преобразование меток в числа в столбце Total_stops.

# acc to the data, price is directly prop to the no. of stops
train_data['Total_Stops'].replace({'non-stop':0,'1 stop':1,'2 stops':2,'3 stops':3,'4 stops':4},inplace=True)
train_data.head()

Шаг 18 — Проверка форм наших 4 фреймов данных.

print(airline.shape)
print(source.shape)
print(destination.shape)
print(train_data.shape)
  • Как мы видим, все эти 4 фрейма данных имеют одинаковое количество строк, а значит, мы все сделали правильно.
  • И теперь мы можем присоединиться к ним.

Шаг 19 — Объедините все 4 фрейма данных.

data_train = pd.concat([train_data,airline,source,destination],axis=1)
data_train.drop(['Airline','Source','Destination'],axis=1,inplace=True)
data_train.head()
  • Соедините все 4 фрейма данных.
  • Удалите столбцы «Авиакомпания», «Источник» и «Назначение».

Шаг 20 — Извлечение данных о поездах.

X = data_train.drop('Price',axis=1)
X.head()
  • Здесь мы берем наши тренировочные данные.
  • Мы взяли все столбцы, кроме столбца «Цена», который является нашим целевым столбцом.

Шаг 21 — Извлечение меток данных поезда.

y = data_train['Price']
y.head()

Шаг 22 — Проверка корреляций между столбцами.

plt.figure(figsize=(10,10))
sns.heatmap(train_data.corr(),cmap='viridis',annot=True)
  • Просто проверка корреляции между различными характеристиками обучающих данных.
  • Мы видим, что Total_stops сильно коррелирует с Duration_hours, что очень очевидно. Если нет. остановок увеличится, увеличится и продолжительность полета в часах.
  • Кроме того, цена сильно коррелирует с общим количеством остановок, потому что увеличение количества остановок также потребует большого количества топлива, а это повысит цену.

Шаг 23 — Первое испытание модели ExtraTreesRegressor для прогнозирования цен на рейсы.

reg = ExtraTreesRegressor()
reg.fit(X,y)

print(reg.feature_importances_)
  • Давайте поместим наши данные в ExtraTreeRegressor и проанализируем важность функций.

Шаг 24 — Проверка важности функции, заданной ExtraTreeRegressor.

plt.figure(figsize = (12,8))
feat_importances = pd.Series(reg.feature_importances_, index=X.columns)
feat_importances.nlargest(20).plot(kind='barh')
plt.show()
  • Total_stops — это функция с наибольшей важностью при определении цены, как мы также видели выше.
  • После этого день путешествия также играет большую роль в определении цены. В выходные обычно цены выше.

Шаг 25 — Разделение наших данных на данные обучения и тестирования.

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 42)

Шаг 26 — Обучение модели случайного лесного регрессора для прогнозирования цен на рейсы.

# Number of trees in random forest
n_estimators = [int(x) for x in np.linspace(start = 100, stop = 1200, num = 12)]

# Number of features to consider at every split
max_features = ['auto', 'sqrt']

# Maximum number of levels in tree
max_depth = [int(x) for x in np.linspace(5, 30, num = 6)]

# Minimum number of samples required to split a node
min_samples_split = [2, 5, 10, 15, 100]

# Minimum number of samples required at each leaf node
min_samples_leaf = [1, 2, 5, 10]

random_grid = {'n_estimators': n_estimators,
               'max_features': max_features,
               'max_depth': max_depth,
               'min_samples_split': min_samples_split,
               'min_samples_leaf': min_samples_leaf}


# Random search of parameters, using 5 fold cross validation, search across 100 different combinations
rf_random = RandomizedSearchCV(estimator = RandomForestRegressor(), param_distributions = random_grid,
                               scoring='neg_mean_squared_error', n_iter = 10, cv = 5, 
                               verbose=1, random_state=42, n_jobs = 1)
rf_random.fit(X_train,y_train)
  • Здесь мы используем RandomizedSearchCV, который просто случайным образом пробует комбинации и видит, какая из них лучше.
  • Мы объявили параметры RandomForestRegressor, которые хотим попробовать.

Шаг 27 — Проверка лучших параметров, которые мы получили с помощью Randomized Search CV.

rf_random.best_params_

Шаг 28 — Делаем прогнозы

# Flight Price Prediction
prediction = rf_random.predict(X_test)

Шаг 29 — Построение остатков.

plt.figure(figsize = (8,8))
sns.distplot(y_test-prediction)
plt.show()
  • Как мы видим, большинство остатков равны 0, что означает, что наша модель хорошо обобщает.

Шаг 30 — График y_test по сравнению с прогнозами.

plt.figure(figsize = (8,8))
plt.scatter(y_test, prediction, alpha = 0.5)
plt.xlabel("y_test")
plt.ylabel("y_pred")
plt.show()
  • Просто сопоставьте наши прогнозы с истинными значениями.
  • В идеале это должна быть прямая линия.

Шаг 31 — Печать метрик.

print(‘r2 score: ‘, metrics.r2_score(y_test,y_pred))

Шаг 32 — Сохранение нашей модели.

file = open('flight_rf.pkl', 'wb')
pickle.dump(rf_random, file)

Окончательные результаты прогнозирования цен на рейсы…

Чтобы узнать больше о машинном обучении, глубоком обучении, компьютерном зрении, НЛП и проектах Flask, посетите мой блог.



Для дальнейшего объяснения кода и исходного кода посетите здесь



Итак, это все для этого блога, ребята, спасибо за то, что прочитали его, и я надеюсь, что вы возьмете что-то с собой после прочтения этого и до следующего раза 👋…