深入理解creme-ml中的流水线艺术

深入理解creme-ml中的流水线艺术

river river 项目地址: https://gitcode.com/gh_mirrors/river12/river

流水线在机器学习中的重要性

流水线(Pipeline)是构建机器学习系统的自然方式。通过流水线,数据科学家可以清晰地看到数据"流动"经过一系列处理步骤的过程。典型的机器学习流程从原始数据开始,经过特征提取、数据标准化、异常值处理等步骤,最终转化为适合机器学习算法输入的格式。

creme-ml作为一个专注于在线学习的Python库,其流水线设计理念与UNIX哲学高度一致,特别适合处理数据流场景。与批处理学习不同,在线学习将数据视为连续不断的观测流,这种场景下流水线的优势尤为明显。

传统过程式编程的局限性

让我们先看一个使用传统过程式编程风格构建的餐厅访客预测模型:

means = (
    feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 7)),
    feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 14)),
    feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 21))
)

scaler = preprocessing.StandardScaler()
lin_reg = linear_model.LinearRegression()
metric = metrics.MAE()

for x, y in datasets.Restaurants():
    # 特征工程
    x['weekday'] = x['date'].weekday()
    x['is_weekend'] = x['date'].weekday() in (5, 6)
    
    # 处理目标变量的滚动均值
    for mean in means:
        x = {**x, **mean.transform_one(x)}
        mean.learn_one(x, y)
    
    # 移除非特征字段
    for key in ['store_id', 'date', 'genre_name', 'area_name', 'latitude', 'longitude']:
        x.pop(key)
    
    # 数据标准化
    scaler.learn_one(x)
    x = scaler.transform_one(x)
    
    # 模型预测和训练
    y_pred = lin_reg.predict_one(x)
    lin_reg.learn_one(x, y)
    
    # 评估指标更新
    metric.update(y, y_pred)

这种实现虽然直观,但存在几个问题:

  1. 代码冗长且重复
  2. 步骤顺序容易出错
  3. 难以防止目标泄漏
  4. 不易复用和扩展

声明式流水线的优势

creme-ml提供了compose.Pipeline来构建声明式流水线,让我们重构上面的代码:

def get_date_features(x):
    weekday = x['date'].weekday()
    return {'weekday': weekday, 'is_weekend': weekday in (5, 6)}

model = compose.Pipeline(
    ('features', compose.TransformerUnion(
        ('date_features', compose.FuncTransformer(get_date_features)),
        ('last_7_mean', feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 7))),
        ('last_14_mean', feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 14))),
        ('last_21_mean', feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 21)))
    )),
    ('drop_non_features', compose.Discard('store_id', 'date', 'genre_name', 'area_name', 'latitude', 'longitude')),
    ('scale', preprocessing.StandardScaler()),
    ('lin_reg', linear_model.LinearRegression())
)

metric = metrics.MAE()

for x, y in datasets.Restaurants():
    y_pred = model.predict_one(x)
    model.learn_one(x, y)
    metric.update(y, y_pred)

这种声明式风格有诸多优势:

  1. 代码更简洁
  2. 步骤顺序明确
  3. 防止了目标泄漏
  4. 更易维护和扩展

更优雅的流水线写法

creme-ml提供了多种简化流水线构建的方法:

1. 自动命名步骤

可以省略步骤名称,creme-ml会自动推断:

model = compose.Pipeline(
    compose.TransformerUnion(
        compose.FuncTransformer(get_date_features),
        feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 7)),
        feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 14)),
        feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 21))
    ),
    compose.Discard('store_id', 'date', 'genre_name', 'area_name', 'latitude', 'longitude'),
    preprocessing.StandardScaler(),
    linear_model.LinearRegression()
)

2. 使用数学运算符组合

可以使用+运算符合并转换器,|运算符构建流水线:

model = (
    compose.FuncTransformer(get_date_features) +
    feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 7)) +
    feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 14)) +
    feature_extraction.TargetAgg(by='store_id', how=utils.Rolling(stats.Mean(), 21))
)

to_discard = ['store_id', 'date', 'genre_name', 'area_name', 'latitude', 'longitude']

model = model | compose.Discard(*to_discard) | preprocessing.StandardScaler()
model |= linear_model.LinearRegression()

3. 自动函数包装

函数会自动包装为FuncTransformer

# 以下两种写法等价
model = compose.FuncTransformer(get_date_features) + ...
model = get_date_features + ...

使用progressive_val_score简化评估

creme-ml提供了evaluate.progressive_val_score来简化在线学习的评估过程:

from river import evaluate

evaluate.progressive_val_score(
    dataset=datasets.Restaurants(),
    model=model,
    metric=metrics.MAE()
)

这种方法不仅代码更简洁,而且确保了评估过程的正确性。

流水线内部机制

creme-ml的Pipeline继承自collections.OrderedDict,每个步骤都有一个名称和对应的转换器/估计器。可以通过标准字典方法访问和操作流水线:

for name, step in model.steps.items():
    print(f"{name}: {type(step).__name__}")

总结

creme-ml的流水线设计提供了以下优势:

  1. 简洁性:通过运算符重载和自动包装减少样板代码
  2. 安全性:防止常见错误如目标泄漏
  3. 可读性:声明式风格更易理解和维护
  4. 灵活性:支持复杂的数据转换和模型组合
  5. UNIX哲学:类似UNIX管道的数据流处理方式

对于在线学习场景,流水线不仅是一种编码风格,更是一种思维方式。掌握creme-ml的流水线艺术,可以让你更高效地构建和维护机器学习系统。

river river 项目地址: https://gitcode.com/gh_mirrors/river12/river

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

范轩锦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值