基于关系型深度学习的自助机器学习
译文 精选 作者: 朱先忠 在本文中,我们将深入探讨一种有趣的深度学习(DL)新方法,称为关系型深度学习(RDL)。我们还将通过在一家电子商务公司的真实数据库(不是数据集!)上做一些RDL来获得一些实践经验。本文将探讨直接在关系数据库上执行机器学习的新方法——关系型深度学习。
本文示例项目数据集的关系模式(作者提供图片)
在本文中,我们将深入探讨一种有趣的深度学习(DL)新方法,称为关系型深度学习(RDL)。我们还将通过在一家电子商务公司的真实数据库(不是数据集!)上做一些RDL来获得一些实践经验。
简介
在现实世界中,我们通常有一个关系数据库,我们想在这个数据库上运行一些机器学习任务。但是,有时候数据库需要高度规范化;这意味着,大量耗时的特征工程和粒度损失,因为我们必须进行大量的聚合操作。更重要的是,我们可以构建无数种可能的特征组合,每种组合都可能产生良好的性能(【文献2】)。这意味着,我们可能会在数据库表格中留下一些与ML任务相关的信息。
这类似于计算机视觉的早期,在深度神经网络出现之前,特征工程任务是基于像素值形式手工完成的。如今,模型直接使用原始像素,而不再依赖于这个中间环节。
关系型深度学习
关系型深度学习(RDL)承诺用表格形式学习实现同样的事情。也就是说,它消除了通过直接在关系数据库上学习来构建特征矩阵的额外步骤。RDL通过将数据库及其关系转换为图来实现这一点;其中,表中的一行成为节点,表之间的关系成为边,行值作为节点特征存储在节点内。
Kaggle的电子商务数据集 ,该数据集包含有关星形模式中电子商务平台的交易数据,其中包含一个核心事实表(交易)和一些维度表。完整的代码可以在 链接 处的笔记本文件中找到。
库来执行RDL。在relbench中,我们必须做的第一件事是指定关系数据库的模式。下面给出一个示例,说明我们如何对数据库中的“事务”表执行此操作。我们将表作为pandas数据帧给出,并指定主键和时间戳列。主键列用于唯一标识实体。时间戳确保我们只能在预测未来交易时从过去的交易中学习。在这种构图中,这意味着信息只能从时间戳较低的节点(即过去)流向时间戳较高的节点。此外,我们指定关系中存在的外键。在这种情况下,事务表具有列“customer_key”,该列是指向“customer_dim”表的外键。
tables['transactions'] = Table(df=pd.DataFrame(t),pkey_col='t_id',fkey_col_to_pkey_table={'customer_key': 'customers','item_key': 'products','store_key': 'stores'},time_col='date')
class EcommerceDataBase(Dataset):#创建你自己的数据集的示例:= pd.Timestamp(year=2018, month=1, day=1)test_timestamp = pd.Timestamp(year=2020, month=1, day=1)def make_db(self) ->).drop(columns=['payment_key', 'time_key', 'unit'])t['date'] = pd.to_datetime(t.date)t = t.reset_index().rename(columns={'index': 't_id'})t['quantity'] = t.quantity.astype(int)t['unit_price'] = t.unit_price.astype(float)products['unit_price'] = products.unit_price.astype(float)t['total_price'] = t.total_price.astype(float)print(t.isna().sum(axis=0))print(products.isna().sum(axis=0))print(stores.isna().sum(axis=0))print(customers.isna().sum(axis=0))tables['products'] = Table(df=pd.DataFrame(products),pkey_col='item_key',fkey_col_to_pkey_table={},time_col=None)tables['customers'] = Table(df=pd.DataFrame(customers),pkey_col='customer_key',fkey_col_to_pkey_table={},time_col=None)tables['transactions'] = Table(df=pd.DataFrame(t),pkey_col='t_id',fkey_col_to_pkey_table={'customer_key': 'customers','item_key': 'products','store_key': 'stores'},time_col='date')tables['stores'] = Table(df=pd.DataFrame(stores),pkey_col='store_key',fkey_col_to_pkey_table={})return>
至关重要的是,作者引入了训练表的概念。这个训练表基本上定义了ML任务。这里的想法是,我们想预测数据库中某个实体的未来状态(即未来值)。我们通过指定一个表来实现这一点,其中每一行都有一个时间戳、实体的标识符和我们想要预测的一些值。id用于指定实体,时间戳指定我们需要预测实体的时间点。这也将限制可用于推断此实体值的数据(即仅过去的数据)。值本身就是我们想要预测的(即真实数据值)。
就我们而言,我们有一个与客户互动的在线平台。我们希望预测客户在未来30天内的收入。我们可以使用DuckDB执行的SQL语句创建训练表。这是RDL的一大优势,因为我们可以仅使用SQL创建任何类型的ML任务。例如,我们可以定义一个查询来选择未来30天内买家的购买数量,以进行流失预测。
df = duckdb.sql(f"""selecttimestamp,customer_key,sum(total_price) as revenuefromtimestamp_df tleft jointransactions taonta.date <= t.timestamp + INTERVAL '{self.timedelta}'and ta.date > t.timestampgroup by timestamp, customer_key""").df().dropna()
结果将是一个数据库表格,其中seller_id是我们想要预测的实体的关键字,收入是目标,时间戳是我们需要进行预测的时间(即我们只能使用到目前为止的数据进行预测)。
下面是创建“customer_venue”任务的完整代码。
class CustomerRevenueTask(EntityTask):# 自定义任务示例:= TaskType.REGRESSIONentity_col = "customer_key"entity_table = "customers"time_col = "timestamp"target_col = "revenue"timedelta = pd.Timedelta(days=30) # 我们想要预测未来的收入。metrics = [r2, mae]num_eval_timestamps = 40def make_table(self, db:>
至此,我们已经完成了大部分工作。其余的工作流程都是类似的,独立于机器学习任务。我能够从relbench提供的 示例笔记本文件
例如,我们需要对节点特征进行编码。在这里,我们可以使用GloVe嵌入(【译者注】个别网文中翻译为“手套嵌入”)来编码所有文本特征,如产品描述和产品名称。
from typing import List, Optionalfrom sentence_transformers import SentenceTransformerfrom torch import Tensorclass GloveTextEmbedding:def __init__(self, device: Optional[torch.device] = None):self.model = SentenceTransformer("sentence-transformers/average_word_embeddings_glove.6B.300d",device=device,)def __call__(self, sentences: List[str]) -> Tensor:return torch.from_numpy(self.model.encode(sentences))
之后,我们可以将这些转换应用于我们的数据并构建图表。
from torch_frame.config.text_embedder import TextEmbedderConfigfrom relbench.modeling.graph import make_pkey_fkey_graphtext_embedder_cfg = TextEmbedderConfig(text_embedder=GloveTextEmbedding(device=device), batch_size=256)data, col_stats_dict = make_pkey_fkey_graph(db,col_to_stype_dict=col_to_stype_dict,# speficied column typestext_embedder_cfg=text_embedder_cfg,# our chosen text encodercache_dir=os.path.join(root_dir, f"rel-ecomm_materialized_cache"),# store materialized graph for convenience)
其余的代码将从标准层构建GNN(图神经网络),对循环训练进行编码,并进行一些评估。为了简单起见,我将把这段代码从本文中删除,因为它非常标准,在各个任务中都是一样的。你可以在链接处查看对应的笔记本文件。
训练结果(作者提供图片)
因此,我们可以训练这个GNN,使其r2达到0.3左右,MAE达到500。这意味着,它预测卖家在未来30天的收入,平均误差为+-500美元。当然,我们不知道这是好是坏,也许通过经典机器学习和特征工程的结合,我们可以得到80%的r2。
结论
关系型深度学习是一种有趣的机器学习新方法,特别是当我们有一个复杂的关系模式时,手动特征工程太费力了。它使我们能够仅使用SQL定义ML任务,这对于那些不深入研究数据科学但仅了解一些SQL的人来说尤其有用。这也意味着,我们可以快速迭代,并对不同的任务进行大量实验。
同时,这种方法也存在自己的问题,例如训练GNN和从关系模式构建图存在不少困难。此外,还有一个问题是,RDL在性能方面能在多大程度上与经典ML模型竞争。过去,我们已经看到,在表格预测问题上,XGboost等模型已被证明比神经网络更好。
参考文献
【1】Robinson,Joshua等人,《RelBench:关系数据库深度学习的基准》,arXiv,2024,。
【2】Fey、Matthias等人,《关系深度学习:关系数据库上的图表示学习》,arXiv预印本arXiv:2312.04615(2023)。
【3】Schlichtkrull,Michael等人。《用图卷积网络建模关系数据》,语义网:第15届国际会议,2018年ESWC,希腊克里特岛伊拉克利翁,2018年6月3日至7日,会议记录#15。施普林格国际出版社,2018年。
译者介绍
朱先忠,社区编辑,专家博客、讲师,潍坊一所高校计算机教师,自由编程界老兵一枚。
Self-Service ML with Relational Deep Learning