⚗️ Calchemy
数据炼金术 — 为 DataFrame 列运算设计的声明式 DSL
让业务方、LLM 和技术方说同一种语言
✨ 一行表达式完成列计算
传统 pandas 代码对业务方不可读,也让 LLM 承担不必要的翻译成本。Calchemy 用一行自然语言风格的表达式完成列计算:
业务人员也能看懂的对比
❌ 传统 pandas —— 业务方看不懂的"天书"
df["毛利率"] = (
df["销售额"] - df["成本"]
) / df["销售额"]
df["毛利率"] = df["毛利率"].apply(
lambda x: f"{x:.2%}" if pd.notna(x) else x
)
✅ Calchemy —— 业务方直接能读
calc(df, "毛利率 = (销售额 - 成本) / 销售额 >>> %")
业务人员不需要理解
df["毛利率"] = ...或apply(lambda x: ...)。Calchemy 表达式本身就是业务语言——毛利率 = (销售额 - 成本) / 销售额,一眼就能看懂并核对。
常见业务场景速查
| 业务需求 | Calchemy 表达式 |
|---|---|
| 计算毛利 | calc(df, "毛利 = 销售额 - 成本") |
| 计算毛利率 | calc(df, "毛利率 = (销售额 - 成本) / 销售额 >>> %") |
| 计算增值税(13%) | calc(df, "税额 = 销售额 * 0.13") |
| 计算净利润 | calc(df, "净利润 = 销售额 - 成本 - 税额") |
| 计算同比增长率 | calc(df, "同比增长 = (本年 - 去年) / 去年 >>> %") |
| 计算客单价(GMV / 订单数) | calc(df, "客单价 = GMV / 订单数") |
| 计算人均产出 | calc(df, "人均产出 = 总产出 / 人数") |
| 计算标准差中的平方项 | calc(df, "平方差 = (X - 均值) ** 2") |
| 计算对数收益率 | calc(df, "对数收益 = log(收盘价 / 昨收)") |
| 计算 n 次方根 | calc(df, "立方根 = root(X, 3)") |
💡 字段名支持中文(
销售额、成本)或常见英文简写(GMV、COGS、DAU),DSL 自动识别。
Calchemy = Calc + Alchemy。把原始数据"炼"成业务指标——这就是数据炼金术。
"Every DataFrame has gold in it. Calchemy helps you extract it."
三方受益
| 角色 | 价值 |
|---|---|
| 🧑💼 业务方 | 直接读懂计算逻辑,无需看 pandas 代码,可自行核对字段定义 |
| 🧑💻 技术方 | 用 DSL 表达式替代重复性 pandas 模板代码,防御性处理内置 |
| 🤖 LLM / AI | 直接输出 DSL 表达式而非 pandas 代码,减少语法错误与调试往返 |
🚀 快速上手
安装
pip install calchemy
或直接将 calchemy/ 目录复制到项目中,仅依赖 pandas 和 numpy。
30 秒示例
import pandas as pd
from calchemy import calc
df = pd.DataFrame({
"销售额": [100, 200, 0, 400],
"成本": [60, 150, 0, 300],
})
# 混合运算 + 百分比格式(字段名直接用中文!)
calc(df, "毛利 = 销售额 - 成本")
calc(df, "毛利率 = 毛利 / 销售额 >>> %")
print(df[["销售额", "成本", "毛利", "毛利率"]])
输出:
销售额 成本 毛利 毛利率
0 100 60 40 40.00%
1 200 150 50 25.00%
2 0 0 0 nan
3 400 300 100 25.00%
📖 DSL 语法
基础格式
新列名 = 列A <运算符> 列B
新列名 = 列A <运算符> 列B >>> 格式
混合运算(支持括号)
gm_rate = (revenue - cogs) / revenue >>> %
tax = revenue * 0.13
操作数:列名(无引号)或数字常量
运算符:+ - * / ** ^
函数:abs(列名) log(列名) log(列名, 底数) sqrt(列名)
格式后缀(>>> 后):%/pct/percent/百分比 → 百分比;省略 → 浮点数
API 列表
| 函数 | 用途 | 示例 |
|---|---|---|
calc() |
🌟 混合运算引擎(推荐) | calc(df, "rate = (a - b) / c >>> %") |
calc_add() |
加法 | calc_add(df, "total = a + b") |
calc_sub() |
减法 | calc_sub(df, "margin = a - b") |
calc_mul() |
乘法 | calc_mul(df, "gmv = qty * price") |
calc_div() |
除法(含零值保护) | calc_div(df, "rate = a / b >>> %") |
💡 简单两操作数运算可用
calc_*helper,混合运算请用calc()。
🛡️ 错误处理(errors 参数)
所有函数均支持 errors 参数,命名对齐 pd.to_datetime(errors=...):
errors 值 |
行为 | 适用场景 |
|---|---|---|
'coerce'(默认) |
NaN 和零分母 → NaN;脏数据 → 0 |
🏭 生产报表,容错优先 |
'raise' |
遇零分母或 NaN 立刻抛 ValueError |
🔍 数据校验,严格模式 |
'ignore' |
跳过问题行,保留原列值 | 🔄 幂等重跑,不覆盖已有结果 |
# 严格模式:有问题直接报错
calc(df, "rate = a / b", errors='raise')
# 忽略模式:有问题跳过
calc(df, "rate = a / b", errors='ignore')
NaN 处理语义
| 情况 | 结果 |
|---|---|
| 任一操作数为 NaN | NaN |
| 除法:0 / 0 | NaN(无意义) |
| 除法:非零 / 0 | 0(脏数据强制归零,避免 ∞) |
| 0 × NaN | NaN(不做隐式填 0) |
🔒 安全性
calc() 使用 ast.parse 受限子集解析表达式:
- ✅ 允许:列名(
Name)、数字常量(Constant)、四则运算(BinOp)、正负号(UnaryOp)、白名单函数(abs/log/sqrt/root) - ❌ 禁止:任意函数调用、属性访问、下标、比较运算、
eval()
# ❌ 以下表达式会被拒绝
calc(df, 'r = __import__("os").system("ls")') # 函数调用
calc(df, 'r = a.__class__') # 属性访问
calc(df, 'r = a > b') # 比较运算
📁 项目结构
calchemy/
├── calchemy/ # 包目录
│ ├── __init__.py # 公共 API 入口
│ ├── types.py # 数据结构:CalcStep, CalcResult
│ ├── utils.py # 校验与格式化工具
│ ├── helpers.py # 运算 helper(四则运算 + 扩展运算)
│ ├── parse.py # AST 解析与拆解
│ ├── calc.py # 混合运算引擎
│ └── chain.py # 链式调用 API
├── tests/ # 测试目录
│ ├── __init__.py
│ └── test_calchemy.py # 测试套件(124 用例)
├── README.md # 中文文档(本文件)
├── README_EN.md # English documentation
└── .gitignore
🗺️ 开发路线
| 阶段 | 内容 | 状态 |
|---|---|---|
| Phase 1 | 除法 calc_div |
✅ 完成 |
| Phase 2 | 加减乘 helper + errors 参数统一 | ✅ 完成 |
| Phase 2.5 | 项目结构重组:标准 Python 包 | ✅ 完成 |
| Phase 3 | 混合运算引擎 calc()(括号 + 常量) |
✅ 完成 |
| Phase 3.5 | 拆解引擎 _calc_decompose():逐步执行 + 血缘追踪 |
✅ 完成 |
| Phase 4 | 链式调用 Calchemy 类 |
✅ 完成(111 测试通过) |
| Phase 4.5 | 扩展运算符(指数 **/^、对数 log、绝对值 abs、平方根 sqrt、n次方根 root) |
✅ 完成(124 测试通过) |
| Phase 5 | LLM Function Calling schema + Skill 文档 | 🔲 规划中 |
| Phase 6 | 跨后端适配(polars / SQL) | 🔲 规划中 |
| Phase 7 | 指标注册表 + 血缘图谱 | 🔲 规划中 |
🎯 设计原则
- 零隐式魔法:NaN 处理语义必须通过
errors参数显式声明 - 列名即文档:DSL 表达式本身就是业务逻辑的可读文档
- 防御性优先:类型检查先于运算,精确报错优于强制转换
- LLM 友好:函数签名和 docstring 以 LLM 直接调用为目标
- 跨后端可迁移:同一套 DSL 可在不同后端执行(Phase 6)
License
Apache 2.0
Metadata
Release files for calchemy 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| calchemy-0.1.0.tar.gz | 33.1 kB | With provenance | Details for calchemy-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| calchemy-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for calchemy-0.1.0-py3-none-any.whl |
Total release size: 59.7 kB
Release files / calchemy-0.1.0.tar.gz
| Download URL | calchemy-0.1.0.tar.gz |
|---|---|
| Size | 33.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
76e6762ab8571dcc4f372a8da04c3e8da905a825eb93542d92e1f9fe0576ed62
|
|
BLAKE2b-256 checksum How to use checksums |
4183b6ada85419edd2ddddb2accbc16acfffe78d7a89ec55c6f4573d93a99793
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 1, 2026.
Transparency logRelease files / calchemy-0.1.0-py3-none-any.whl
| Download URL | calchemy-0.1.0-py3-none-any.whl |
|---|---|
| Size | 26.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
55a01ef20339c691092848ecd943195a5a69e705213dc3e374eba467b3954645
|
|
BLAKE2b-256 checksum How to use checksums |
4964ec8deb2f83796dfc3fd8a8f84abfab4d267f5b08acca3418048ec107c755
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 1, 2026.
Transparency logSecurity for calchemy 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for calchemy-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jun 1, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.