Bagaimana cara meramalkan tiket pesawat?

Halo semuanya!

Ini adalah artikel ketiga tentang bagaimana saya membuat layanan kecil dan nyaman, yang secara teori harus membantu perencanaan perjalanan. Dalam artikel ini saya akan berbicara tentang cara memprediksi tiket pesawat dengan data Clickhouse, Catboost, dan 1TB *.

gambar

Untuk apa ini?


Salah satu fitur utama dari cheapster.travel adalah kombinasi fleksibel dari rute yang kompleks (lebih banyak di artikel sebelumnya ). Untuk menggabungkan "semua-dengan-semua", cache agregator digunakan, di mana tidak selalu ada tiket yang jarang dicari, dan mereka sangat kurang untuk membangun rute yang kompleks. Itu tiket panas (murah) yang menjadi basis rute kompleks di sana , tetapi tidak cukup 1-2 segmen tiket "normal" (dengan harga reguler, bukan pada arah yang paling populer). Masalah inilah yang membuat saya perlu membangun model yang dapat memprediksi harga tiket pesawat.

Formalisasi tugas


  • Anda harus dapat memprediksi tiket untuk penerbangan langsung (hanya pulang pergi)
  • Anda harus dapat secara teratur memprediksi dan menyimpannya dalam database (skenario sederhana)
  • Harus dapat memprediksi "on the fly" (skenario kompleks)
  • Ini semua terjadi pada perangkat keras yang sangat terbatas - karenanya, manipulasi minimum dengan data dalam jumlah besar

Bagaimana cara melakukannya?


Untuk memulainya, kami akan melatih model: menyiapkan dataset, menyoroti jumlah maksimum fitur dalam kolom, mengunggahnya ke tsv, memuatnya ke DataFrame / Pool, menganalisis, memilih parameter ... Berhenti, kami memiliki terlalu banyak data dan mereka tidak sesuai dengan memori , - menangkap kesalahan berikut:

MemoryError: Unable to allocate array with shape (38, 288224989) and data type float64
OSError: [Errno 12] Cannot allocate memory

Untuk mengatasi keterbatasan ini, perlu untuk belajar berulang-ulang dalam bentuk kecil, sepertinya ini:

model = CatBoostRegressor(cat_features=cat_features,
          iterations=100,
          learning_rate=.5,
          depth=10,
          l2_leaf_reg=9,
          one_hot_max_size=5000)

for df in tqdm(pd.read_csv('history.tsv', sep='\t', 
                           na_values=['\\N'], 
                           chunksize=2_000_000)):
    ...
     model.fit(X=df[df.columns[:-1]][:train_size].values,
                  y=df['price'][:train_size].values,
                  eval_set=eval_pool,
                  verbose=False,
                  plot=False,
                  init_model=model) # <--        

Hasilnya adalah model dengan RMSE ~ 100 - secara umum, saya akan senang dengan hasil seperti itu, tetapi setelah sedikit analisis dan "normalisasi" prediksi (negatif dan nilai yang sangat berbeda dari nilai minimum / min dalam sejarah dibawa ke batas yang sesuai dari harga historis) . Setelah itu, target metrik adalah ~ 80, dengan mempertimbangkan fakta bahwa dalam pengalaman saya, hampir tidak ada logika dan akal sehat dalam menentukan harga tiket pesawat.

Fitur yang paling mempengaruhi harga:

gambar

Statistik untuk fitur "Jarak antar kota":

gambar

Hebat, kami memiliki model - sekarang saatnya untuk menggunakannya. Pertama-tama, tambahkan model KX, ini dilakukan dengan konfigurasi sederhana:

Konfigurasi
<models>
    <model>
        <!-- Model type. Now catboost only. -->
        <type>catboost</type>
        <!-- Model name. -->
        <name>price</name>
        <!-- Path to trained model. -->
        <path>/opt/models/price_iter_model_2.bin</path>
        <!-- Update interval. -->
        <lifetime>0</lifetime>
    </model>
</models>


Kami membuat proses prediksi reguler - cukup mudah untuk melakukannya menggunakan Apache Airflow.

DAG yang dihasilkan terlihat seperti ini
image
DAGa ( Airflow):

SimpleHttpOperator
insert_ow_in_tmp = SimpleHttpOperator(
    task_id='insert_ow_in_tmp',
    http_conn_id='clickhouse_http',
    endpoint=dll_endpoint,
    method='POST',
    data=sql_templates.INSERT_OW_PREDICTIONS_IN_TMP,
    pool='clickhouse_select',
    dag=dag
)



Untuk prediksi "on the fly" menggunakan sql biasa:

select origin, destination, date,
         modelEvaluate('price', *)  predicted_price -- ,   
from log.history

+--------+-------------+------------+-----------------+
| origin | destination | date       | predicted_price |
+--------+-------------+------------+-----------------+
| VKO    | DEB         | 2020-03-20 | 3234.43244      |
+--------+-------------+------------+-----------------+
--* ,   

Saya ingin mengganti fakta bahwa pendekatan semacam itu telah dipilih, bukan hanya karena lebih mudah diterapkan - masih ada beberapa kelebihannya:

  • Tidak perlu mengunggah data ke luar KH (ini berarti lebih cepat dan lebih murah pada beban pada setrika)
  • Tidak perlu melakukan proses etl (lebih mudah = lebih dapat diandalkan)

Kami sedikit memperbaiki API dan front-end dan mendapatkan prediksi yang telah lama ditunggu.

Prediksi ini juga sangat cocok dengan bagian sejarah harga tiket Maskapai Penerbangan :

gambar

Fungsionalitas ini tersedia di cheapster.travel/history (akan terbuka secara miring di ponsel, hanya layar besar).

Itu saja, semua hari yang produktif!

Artikel Sebelumnya


Upaya untuk memecahkan masalah memilih tiket pesawat sebelum liburan
Upaya untuk memecahkan masalah memilih tiket pesawat sebelum liburan # 2

Fitur menarik lainnya


Combinator dari rute yang sulit
Tiket kompleks (segitiga)

PS
Penting! Jangan menganggap prediksi ini sebagai sesuatu yang membantu Anda memilih tanggal pembelian - model mungkin tidak memprediksi dengan benar, apalagi, kecukupannya belum diverifikasi oleh saya atau orang lain (semua atas risiko dan risiko Anda sendiri, tanpa jaminan).

1TB * - ini adalah jika Anda mengunggah ke tsv, di KX dibutuhkan urutan besarnya kurang.

UPD:

Isu-isu Top yang Tidak Terlihat Saat Menggunakan Bundel Catboost - Clickhouse


  1. Fitur-fitur kategorikal dalam KH mengubah urutan dan menjadi pada akhir (dan bukan pada urutan yang selama pelatihan);
  2. modelEvaluate mengembalikan null - Anda perlu memeriksa apakah Anda memiliki nilai null dalam fitur, jika Anda perlu menggantinya dengan nan
  3. Dalam versi baru ada momen yang tidak terlihat dengan format konfigurasi untuk KX, dijelaskan di sini

All Articles