如何预测机票价格?

大家好!

这是有关我如何提供小型舒适服务的第三篇文章,从理论上讲,这应该有助于旅行计划。在本文中,我将讨论如何通过Clickhouse,Catboost和1TB *数据来预测机票价格。

图片

这是为了什么


cheapster.travel 的主要功能之一是复杂路线的灵活组合(在上一篇文章中有更多介绍)。为了将“所有所有”组合在一起,使用了一个聚合器缓存,其中并不总是存在很少被搜索到的票证,并且它们非常缺乏构建复杂的路线。那些。在其上热门票(廉价)到基座复杂路径存在,但“正常”的门票(在正常价格,而不是最流行的方向)不够1-2段。正是这个问题导致我需要建立一个可以预测机票价格的模型。

任务形式化


  • 您需要能够预测直飞机票(仅限往返)
  • 您需要能够定期预测并将其存储在数据库中(简单方案)
  • 需要能够“实时”预测(复杂的情况)
  • 所有这一切都在非常有限的硬件上进行-因此,对大量数据的最少操作

怎么做?


首先,我们将训练模型:准备数据集,在列中选择最大数量的特征,将其上传到tsv,将其加载到DataFrame / Pool中,进行分析,然后选择参数...停止,我们有太多数据,它们不适合内存,-捕获以下错误:

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

为了克服此限制,有必要以小段式进行迭代学习,如下所示:

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

结果是一个RMSE〜100的模型-总的来说,我会对这样的结果感到满意,但是在对预测进行了一点分析和``标准化''之后(与历史上的最小/最大值相差很大的负值和值被带到了历史价格的相应边界) 。之后,根据我的经验,目标指标为〜80,考虑到机票定价几乎没有逻辑和常识。

对价格影响最大

图片

的功能:“城市之间的距离”功能的统计信息:

图片

太好了,我们有了一个模型-现在是时候使用它了。首先,添加KX模型,这是通过一个简单的配置完成的:

设定档
<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>


我们进行定期的预测过程-使用Apache Airflow进行预测非常容易。

生成的DAG看起来像这样
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
)



对于使用普通sql的“即时”预测:

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

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

我要替换这样一个事实,即选择了这种方法,不仅是因为它更易于实现-还有一些优点:

  • 无需将数据上传到KH的外部(这意味着熨斗上的负载更快,更便宜)
  • 无需进行etl流程(更轻松=更可靠)

我们对API和前端进行了稍微的校正,并获得了期待已久的预测。

这些预测也非常适合“机票价格历史记录”部分:该

图片

功能可在cheapster.travel/history中获得(它会歪曲地在移动设备上打开,仅在大屏幕上显示)。

仅此而已,这真是富有成效的一天!

以前的文章


解决假期之前选择机票问题的尝试#2解决假期之前选择机票问题的
尝试

另一个有趣的功能


困难路线的
组合复杂的车票(三角形)

PS
重要!不要将这些预测当作可以帮助您选择购买日期的方式-该模型可能无法正确预测,而且我或任何其他人尚未验证其适当性(后果自负,没有保证)。

1TB *-如果您上传到tsv,则在KX中所需的时间要少一个数量级。

UPD:

使用Catboost捆绑包时最明显的问题-Clickhouse


  1. KH中的分类功能会更改顺序并变为结尾(而不是训练期间的顺序);
  2. modelEvaluate返回null-您需要检查要素中是否有null值,是否需要将其替换为nan
  3. 在新版本中有一个不明显的时刻与KX的配置格式,描述在这里

All Articles