Wie prognostiziere ich den Flugpreis?

Hallo alle zusammen!

Dies ist der dritte Artikel darüber, wie ich einen kleinen und komfortablen Service mache, der theoretisch bei der Reiseplanung helfen sollte. In diesem Artikel werde ich darüber sprechen, wie der Flugpreis mit Clickhouse-, Catboost- und 1 TB * -Daten vorhergesagt werden kann.

Bild

Wofür ist das?


Eines der Hauptmerkmale von cheapster.travel ist die flexible Kombination komplexer Routen (mehr im vorherigen Artikel ). Um "All-with-All" zu kombinieren, wird ein Aggregator-Cache verwendet, in dem nicht immer Tickets gesucht werden, nach denen selten gesucht wird, und es ihnen schmerzlich fehlt, komplexe Routen zu erstellen. Jene. heiße Tickets (billig), auf denen komplexe Routen basieren , aber nicht genug 1-2 Segmente der "normalen" Tickets (zum regulären Preis, nicht in der beliebtesten Richtung). Es war dieses Problem, das mich dazu brachte, ein Modell zu bauen, das den Flugpreis vorhersagen konnte.

Aufgabenformalisierung


  • Sie müssen in der Lage sein, Tickets für Direktflüge vorherzusagen (nur Hin- und Rückflug).
  • Sie müssen dies regelmäßig vorhersagen und in der Datenbank speichern können (einfaches Szenario).
  • Müssen in der Lage sein, "on the fly" vorherzusagen (komplexes Szenario)
  • Dies alles geschieht auf einer sehr begrenzten Hardware - daher ein Minimum an Manipulation mit großen Datenmengen

Wie kann man das machen?


Zunächst trainieren wir das Modell: Bereiten Sie das Dataset vor, markieren Sie die maximale Anzahl von Features in den Spalten, laden Sie es auf tsv hoch, laden Sie es in den DataFrame / Pool, analysieren Sie, wählen Sie die Parameter aus ... Stop, wir haben zu viele Daten und sie passen nicht in den Speicher , - folgende Fehler abfangen:

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

Um diese Einschränkung zu umgehen, musste iterativ in kleinen Stücken gelernt werden. Es sieht folgendermaßen aus:

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) # <--        

Das Ergebnis war ein Modell mit RMSE ~ 100 - im Allgemeinen wäre ich mit einem solchen Ergebnis zufrieden gewesen , aber nach einer kleinen Analyse und "Normalisierung" der Vorhersagen (Negative und Werte, die sich stark von den Min / Max-Werten in der Geschichte unterscheiden, werden an die entsprechenden Grenzen der historischen Preise gebracht). . Danach beträgt die Zielmetrik ~ 80, unter Berücksichtigung der Tatsache, dass es meiner Erfahrung nach fast keine Logik und keinen gesunden Menschenverstand bei der Preisgestaltung von Flugtickets gibt.

Funktionen, die den Preis am meisten beeinflussen:

Bild

Statistiken für Funktionen „Entfernung zwischen Städten“:

Bild

Großartig, wir haben ein Modell - jetzt ist es Zeit, es zu verwenden. Fügen Sie zunächst das KX-Modell hinzu. Dies erfolgt mit einer einfachen Konfiguration:

Konfig
<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>


Wir führen einen regelmäßigen Vorhersageprozess durch - es ist einfach genug, dies mit Apache Airflow zu tun.

Die resultierende DAG sieht so aus
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
)



Für die Vorhersage "on the fly" mit gewöhnlichem SQL:

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

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

Ich möchte die Tatsache ersetzen, dass dieser Ansatz gewählt wurde, nicht nur, weil er einfacher zu implementieren ist - es gibt immer noch Pluspunkte:

  • Es ist nicht erforderlich, Daten außerhalb des KH hochzuladen (dies bedeutet eine schnellere und kostengünstigere Belastung des Bügeleisens).
  • Keine Notwendigkeit, etl-Prozesse durchzuführen (einfacher = zuverlässiger)

Wir korrigieren die API und das Front-End leicht und erhalten die lang erwarteten Vorhersagen.

Diese Vorhersagen passen auch gut in den Abschnitt Preisentwicklung für Flugtickets: Die

Bild

Funktionalität ist unter cheapster.travel/history verfügbar (sie wird auf dem Handy schief geöffnet, nur auf großen Bildschirmen).

Das ist alles ein produktiver Tag!

Vorherige Artikel


Ein Versuch, das Problem der Auswahl von Flugtickets vor dem Urlaub zu lösen Ein Versuch, das Problem der Auswahl von Flugtickets vor dem Urlaub
zu lösen # 2

Ein weiteres interessantes Feature


Kombinator schwieriger Routen
Komplexe Tickets (Dreiecke)

PS
Wichtig! Nehmen Sie diese Vorhersagen nicht als etwas, das Ihnen bei der Auswahl eines Kaufdatums hilft - das Modell kann möglicherweise nicht richtig vorhersagen, außerdem wurde seine Angemessenheit weder von mir noch von anderen überprüft (alles auf eigene Gefahr und Gefahr, ohne Garantien).

1 TB * - Dies ist, wenn Sie auf tsv hochladen, in KX dauert es eine Größenordnung weniger.

UPD:

Die wichtigsten nicht offensichtlichen Probleme bei der Verwendung von Catboost-Bundles - Clickhouse


  1. Kategoriale Merkmale in KH ändern die Reihenfolge und werden am Ende (und nicht in der Reihenfolge, die während des Trainings war);
  2. modelEvaluate gibt null zurück - Sie müssen überprüfen, ob Sie Nullwerte in Features haben, wenn Sie diese durch nan ersetzen müssen
  3. In dem neuen Versionen gibt es einen nicht offensichtlichen Moment mit dem Config - Format für KX, beschrieben hier

All Articles