PyO3-Polars OptBinning extension with Rust-side optimization kernels
Project description
polars-optbinning
基于 Rust 的 Polars DataFrame 规则最优分箱引擎。注意项目仍处于早期开发阶段,每个版本API可能会发生重大破坏性变更。
核心 API 是 BinningTransformer:为一个或多个特征拟合经优化的分箱规则,保留拟合后的规则组,并在 Polars 管道中复用。
安装
从 PyPI 安装已发布的包:
pip install polars-optbinning
本地开发:
uv sync --group dev
uv run maturin develop --release
用法
import polars as pl
from polars_optbinning import BinningTransformer, Objective, Stat
df = pl.DataFrame(
{
"x1": [1.0, 1.2, 2.0, 2.2, 3.1, 3.4, 4.5, 5.0, 5.2, 6.0],
"x2": [10.0, 9.8, 9.5, 8.9, 8.1, 7.3, 6.5, 5.9, 5.1, 4.2],
"y": [0, 0, 0, 1, 0, 1, 1, 1, 1, 1],
}
)
transformer = BinningTransformer(
features=[pl.col("x1"), pl.col("x2")],
target=pl.col("y"),
)
transformer.fit(
df,
objective=Objective.iv(),
mapping=[Stat.woe(), Stat.count()],
max_bins=4,
)
eager_out = transformer.transform(df)
pipeline_out = df.with_columns(transformer.transform_())
count_out = transformer.transform(df, extra_mapping=[Stat.count()])
print(eager_out)
print(pipeline_out)
print(count_out)
print(transformer.summary())
summary() 可以重新执行当前规则并计算与 transform 映射无关的统计量:
stats = transformer.summary(
extra_stat=[
Stat.count(),
Stat.feat_avg(),
Stat.target_avg(),
Stat.avg("x2"),
Stat.sum("x2"),
Stat.woe(),
]
)
feat_avg()、feat_min() 和 feat_max() 始终返回列表,覆盖每个规则组所用的特征。avg(expr)、min(expr)、max(expr) 和 sum(expr) 返回单个 Polars 表达式的标量统计量。基于表达式的输出名称从表达式派生,例如 Stat.avg("x2") 产生 x2_avg。sum()、woe()、iv() 和 event_rate() 默认使用初始化时指定的目标,也接受显式表达式。
拟合后的转换器会复用其选定的训练数据。传递 summary(extra_stat=[...], df=new_df) 可以在另一数据集上计算统计量。通过解析或手动构造的转换器需要提供 df,并可以使用显式表达式统计量(如 Stat.woe("label"));依赖默认目标的统计量需要 BinningTransformer(target=...)。fit() 或 parse() 中提供的 mapping 仍然是 transform() 和 transform_() 产生的显式模式;未被 mapping 选中的规则统计量不会自动展开到 transform 列中。transform(df, extra_mapping=[...]) 和 transform_(extra_mapping=[...]) 可以在本次输出中临时追加规则统计映射,缺失的统计量会像 summary(extra_stat=...) 一样先按当前数据重新聚合,且不修改转换器自身。表达式版 transform_() 没有显式 df 参数,因此会使用 fit() 时保存的训练视图;解析或手动构造的转换器仍需要这些统计量已存在于规则中。
两两 2D 分箱为每个特征对创建一个特征:
pairwise = BinningTransformer(
features=[pl.col("x1"), pl.col("x2")],
target=pl.col("y"),
prefix="pair_",
)
pairwise.fit(
df,
objective=Objective.iv(),
mapping=[Stat.index()],
max_bins=4,
mode="pairwise_2d",
progress=True,
)
out = df.with_columns(pairwise.transform_())
连续目标回归示例见 examples/example_linear.py。
原生 XGBoost 和 LightGBM 树模型可以解析为可复用的规则组:
model = BinningTransformer.parse(
"examples/models/multiclass_xgb.json",
mapping=[Stat.bin_value()],
prefix="xgb_",
)
tree_outputs = df.with_columns(model.transform_())
raw_margin = df.with_columns(prediction=model.predict_())
probability = df.with_columns(prediction=model.predict_(output="probability"))
classes = df.with_columns(prediction=model.predict_(output="class"))
eager_prediction = model.predict(df, output="class")
parse() 接受 XGBoost save_model() JSON/UBJ 文件和 LightGBM Booster.save_model() 文本文件、路径及可读文件对象。解析后的转换器每棵树暴露一个可编辑的 RuleGroup,不可再次拟合。原生模型训练、序列化、解析以及与 Polars 预测对比的完整示例见 examples/example_multiclass_models.py。
也支持手动构建规则引擎:
from polars_optbinning import Condition, Rule, RuleGroup
group = RuleGroup(
"x",
["x"],
[
Rule(Condition.interval("x", None, 2.0), [Stat.const(0.1)]),
Rule(Condition.interval("x", 2.0, None), [Stat.const(0.9)]),
],
[Stat.const(0.0)],
)
engine = BinningTransformer(groups=[group])
out = pl.DataFrame({"x": [1.0, 2.5]}).with_columns(engine.transform_())
条件可以跨一个或多个特征进行集合组合:
high_risk = (Condition.interval("age", 65.0, None) & Condition.is_in("region", [1.0, 2.0]))
eligible = high_risk | Condition.interval("score", 700.0, None)
excluded = eligible - Condition.is_in("region", [9.0])
assert excluded.features == ["age", "region", "score"]
excluded = excluded.simplify()
group = RuleGroup(
"decision",
["age", "region", "score"],
[
Rule(excluded, [Stat.const(1.0)]),
Rule(Condition.otherwise(), [Stat.const(0.0)]),
],
[Stat.const(0.0)],
)
otherwise 是可选的,但存在时必须作为最后一条规则。空组以及没有 otherwise 规则的未匹配行输出 null。拟合后的分箱组按拟合计数的降序排列,且始终包含一条最终的 otherwise 规则。
规则可以编译为显式的二进制执行链:
group.compile()
assert group.execution_kind == "rule_chain"
Perpetual GBDT
通过同一个转换器支持多维梯度提升:
model = BinningTransformer(features=["x1", "x2"], target="y").fit(
df,
mode="gbdt",
objective=Objective.squared_loss(),
extra_params={
"budget": 0.5,
"iteration_limit": 100,
"categorical_features": ["x2"],
},
)
raw = df.select(model.predict_())
tree_outputs = df.select(model.transform_())
importance = model.feature_importance()
分类使用 Objective.log_loss()。整数类别标签被保留,包括非连续标签。extra_params 会进行严格校验,与特征相关的设置使用特征名称而非列索引。
树规则暴露 Stat.gain(),定义为从根到叶子路径上的累积分裂增益。feature_importance() 则对每个内部分裂恰好计数一次,返回 feature、gain、gain_normalized 和 split_count。结构化的规则编辑会使原始树的重要性信息失效。包含类别和缺失值处理的泰坦尼克生存分类示例见 examples/example_perpetual.py。
Rust 集成当前锁定 perpetual 3.0.0-rc.2,这是第一个基于稳定 Rust 构建的兼容版本;perpetual 2.1.0 需要仅限 nightly 的编译器特性。
当前范围
- 通过
BinningTransformer.fit的多特征优化 1D 分箱。 - 类型化的
Objective和Stat选择器。 - 即时
transform(df)和表达式友好的transform_()。 summary()以 Polars DataFrame 格式返回拟合的规则统计量。- 通过
mode="pairwise_2d"的两两 2D 矩形分箱。 - XGBoost/LightGBM 数值树解析、叶子规则转换及模型预测。
ND 优化拟合在可复用规则引擎接口稳定期间暂时搁置。
发布
发布脚本会验证 pyproject.toml 和 Cargo.toml 使用相同的版本号,构建优化后的 wheel 和源码分发包,发布到 PyPI,创建对应的 v<version> Gitee 标签,并将文件同步到 Gitee Release。
推荐使用 Token 认证:
$env:GITEE_TOKEN = "<personal-access-token>"
$env:MATURIN_PYPI_TOKEN = "<pypi-api-token>"
python scripts/gitee_release.py
PYPI_API_TOKEN 可作为别名使用。也支持账号/密码认证,通过 MATURIN_USERNAME + MATURIN_PASSWORD 或 PYPI_USERNAME + PYPI_PASSWORD。
PyPI 分发包是不可变的。重复运行时,--skip-existing 会跳过已发布的文件,同时允许上传其他平台对应的 wheel。Gitee Release 会更新,同名附件会被替换。已有 wheel 会被保留。
设置 SKIP_BUILD=1 可上传已在 WHEEL_DIR(默认为 dist)中的文件,SKIP_PYPI=1 仅同步到 Gitee,SKIP_GITEE=1 仅发布到 PyPI。所有凭证必须存储在 CI 服务的安全变量存储中。
发布检查清单:
- 同时更新
pyproject.toml和Cargo.toml中的版本号。 - 更新
CHANGELOG.md。 - 运行 Clippy 和 Python 测试套件。
- 在应打版本标签的提交上运行发布脚本。
项目政策请参考 CONTRIBUTING.md、SECURITY.md 和 LICENSE。
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file polars_optbinning-0.2.5.tar.gz.
File metadata
- Download URL: polars_optbinning-0.2.5.tar.gz
- Upload date:
- Size: 126.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c5433b33de80fb72b3961e36fe90c4cd68ef23d2428667b4388b1559f8cbd98
|
|
| MD5 |
707c6e4a207c85916e2a8c97260a5daa
|
|
| BLAKE2b-256 |
83ceb4d935acd851bb1dc5e9da39bf529215a6cabab3215ffa4e13a5f815ae21
|
File details
Details for the file polars_optbinning-0.2.5-cp39-abi3-win_amd64.whl.
File metadata
- Download URL: polars_optbinning-0.2.5-cp39-abi3-win_amd64.whl
- Upload date:
- Size: 5.9 MB
- Tags: CPython 3.9+, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: maturin/1.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d3e74ff5478b24485d0eeba4d16e5088be30005a2adaeef852e809754a5f5900
|
|
| MD5 |
89f29d3dbb55cfaee7ced868f4fa2609
|
|
| BLAKE2b-256 |
f244954bd74fec46680c3de390ca938ff142cfb00d809a9ad6d936a7be90ce61
|