Polars如何无损精度向下转换浮点数据类型?
Polars 无损向下转换浮点列数据类型的方法
首先明确:你观察到的差异本质是 Polars的shrink_dtype与pandasdowncast="float"的逻辑不同:
polars.Expr.shrink_dtype是直接强制将float64转换为float32,不会检查值是否能被目标类型精确表示,所以像2.7这种无法用二进制浮点精确存储的数值,转换后会出现精度偏差。- pandas的
pd.to_numeric(downcast="float")会先验证每个值是否能被float32精确表示,仅对能无损转换的值进行类型压缩,无法精确表示的会保留float64类型。
在Polars中,你可以通过手动验证精度+条件转换的方式实现类似pandas的无损向下转换逻辑,具体实现如下:
实现代码示例
import polars as pl # 示例数据 df = pl.DataFrame({ "float_col": [2.0, 3.5, 2.7, 1.0000000001] }) # 自定义无损转换逻辑:仅保留能被float32精确表示的值,其余保留float64 def safe_downcast_float(col: str) -> pl.Expr: casted = pl.col(col).cast(pl.Float32) return pl.when(casted.cast(pl.Float64) == pl.col(col)) .then(casted) .otherwise(pl.col(col)) # 应用转换 df_optimized = df.with_columns(safe_downcast_float("float_col")) # 查看结果和类型 print(df_optimized) print(df_optimized.schema)
逻辑说明
- 先将列转换为
float32,再转换回float64与原数值比较:- 如果相等,说明该值可以被
float32精确存储,保留转换后的float32类型 - 如果不相等,说明存在精度损失,保留原
float64类型
- 如果相等,说明该值可以被
- 这种方法会生成混合类型的列(部分值是
float32,部分是float64),Polars会自动将列的类型标记为pl.Float64(取所有值的公共超类型),但实际存储中会对可压缩的值使用float32,达到类似pandas的无损压缩效果。
如果你需要强制让整个列统一为float32且接受部分值的精度损失,直接用pl.col(col).cast(pl.Float32)即可;如果要严格无损,就用上述条件转换的方式。
内容的提问来源于stack exchange,提问作者sci9
相关产品推荐
相关产品推荐

