
本文介绍在 DuckDB 中对包含数值列表的列进行行内归一化(即每行列表元素除以其自身总和)的两种简洁高效方法:使用 list_transform 函数或列表推导式语法。
本文介绍在 duckdb 中对包含数值列表的列进行行内归一化(即每行列表元素除以其自身总和)的两种简洁高效方法:使用 `list_transform` 函数或列表推导式语法。
在 DuckDB 中处理嵌套数据类型(如 LIST)时,需注意其向量化函数与标量运算的语义差异。直接使用 / 运算符作用于列表列(如 c / list_sum(c))会触发类型不匹配错误,因为 DuckDB 不支持原生的“列表-标量”逐元素除法运算符重载。正确做法是显式遍历列表并应用归一化逻辑。
✅ 推荐方案一:使用 list_transform
list_transform 是 DuckDB 提供的高阶函数,接受一个列表和一个 lambda 表达式,对列表中每个元素独立计算并返回新列表:
SELECT *,
list_transform(c, x -> x / list_sum(c)) AS c_normalised
FROM df;
该写法语义清晰、兼容性强,适用于所有 DuckDB ≥ v0.9.2 版本。
✅ 推荐方案二:使用列表推导式(更 Pythonic)
DuckDB 支持类 Python 的列表推导语法([expr for x in list]),代码更紧凑且可读性高:
SELECT *,
[x / list_sum(c) FOR x IN c] AS c_normalised
FROM df;
⚠️ 注意事项:
-
list_sum(c)在推导式中按行求值(即每行独立计算自身列表总和),不是全表聚合; - 所有参与运算的数值将自动提升为
DOUBLE类型,确保浮点精度; - 若列表可能为空(
[]),list_sum(c)返回NULL,导致整行归一化结果为NULL;生产环境建议前置过滤或使用COALESCE(list_sum(c), 1)防错(需结合业务逻辑判断是否合理); - 列表推导式要求 DuckDB ≥ v0.10.0(推荐升级至最新稳定版以获得完整支持)。
总结
DuckDB 虽不支持 Polars 那样链式、面向列的 .list 方法链,但通过 list_transform 和列表推导式,同样能以声明式、高性能的方式完成复杂列表变换任务。二者本质等价,可根据团队编码风格偏好选择——前者更显式稳健,后者更简洁直观。










