A declarative DSL for DataFrame column calculations
Project description
⚗️ 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
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 calchemy-0.1.0.tar.gz.
File metadata
- Download URL: calchemy-0.1.0.tar.gz
- Upload date:
- Size: 33.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
76e6762ab8571dcc4f372a8da04c3e8da905a825eb93542d92e1f9fe0576ed62
|
|
| MD5 |
b1439bc628dc959fa1bd9ec87ffff74d
|
|
| BLAKE2b-256 |
4183b6ada85419edd2ddddb2accbc16acfffe78d7a89ec55c6f4573d93a99793
|
Provenance
The following attestation bundles were made for calchemy-0.1.0.tar.gz:
Publisher:
publish.yml on CoderMoray/Calchemy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
calchemy-0.1.0.tar.gz -
Subject digest:
76e6762ab8571dcc4f372a8da04c3e8da905a825eb93542d92e1f9fe0576ed62 - Sigstore transparency entry: 1690887886
- Sigstore integration time:
-
Permalink:
CoderMoray/Calchemy@ca226434c848ef541c1d070af3fbc083c968c962 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/CoderMoray
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ca226434c848ef541c1d070af3fbc083c968c962 -
Trigger Event:
push
-
Statement type:
File details
Details for the file calchemy-0.1.0-py3-none-any.whl.
File metadata
- Download URL: calchemy-0.1.0-py3-none-any.whl
- Upload date:
- Size: 26.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55a01ef20339c691092848ecd943195a5a69e705213dc3e374eba467b3954645
|
|
| MD5 |
81819be9c7d0c9aea4f55cd71560f36b
|
|
| BLAKE2b-256 |
4964ec8deb2f83796dfc3fd8a8f84abfab4d267f5b08acca3418048ec107c755
|
Provenance
The following attestation bundles were made for calchemy-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on CoderMoray/Calchemy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
calchemy-0.1.0-py3-none-any.whl -
Subject digest:
55a01ef20339c691092848ecd943195a5a69e705213dc3e374eba467b3954645 - Sigstore transparency entry: 1690887904
- Sigstore integration time:
-
Permalink:
CoderMoray/Calchemy@ca226434c848ef541c1d070af3fbc083c968c962 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/CoderMoray
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ca226434c848ef541c1d070af3fbc083c968c962 -
Trigger Event:
push
-
Statement type: