Polars:带后缀条件乘数的字符串转浮点数问题求解
Polars处理K/MM后缀字符串转百万单位浮点数列的解决方案
问题原因
你的代码报错是因为Polars的when/otherwise是列级向量操作,并非逐行判断后执行对应分支。也就是说,otherwise分支会尝试对整个列执行处理——带MM的行虽然进入then分支,但otherwise分支的代码依然会对这些行操作,而这些行的字符串没被替换掉MM,导致转Float32失败。
单次列读取的解决方案
我们可以通过一次提取数字和后缀,再统一计算的方式实现,只需要读取目标列一次:
import polars as pl df = pl.DataFrame({ "col1": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"], "col2": ["500K", "1MM", "25K", "2.5MM", "2MM", "600K", "800K", "1.5MM", "5MM", "350k"] }) result = df.with_columns( # 一次提取数字部分和后缀到结构体 pl.col("col2") .str.extract(r"^([\d.]+)(MM|K|k)$") .struct.rename_fields(["numeric", "suffix"]) # 转换数字类型并计算换算系数 .with_fields( numeric=pl.col("numeric").cast(pl.Float32), multiplier=pl.when(pl.col("suffix") == "MM") .then(1.0) # MM直接对应百万单位 .otherwise(0.001) # K/k转百万单位需除以1000 ) # 计算最终值 .apply(lambda x: x["numeric"] * x["multiplier"], return_dtype=pl.Float32) .alias("col2") ) print(result)
更简洁的向量式实现(同样仅读取一次列)
如果偏好纯向量操作,避免apply,可以用以下写法:
import polars as pl df = pl.DataFrame({ "col1": ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"], "col2": ["500K", "1MM", "25K", "2.5MM", "2MM", "600K", "800K", "1.5MM", "5MM", "350k"] }) result = df.with_columns( ( # 提取数字部分并转浮点 pl.col("col2").str.replace(r"(MM|K|k)$", "").cast(pl.Float32) * # 根据后缀判断换算系数 pl.when(pl.col("col2").str.contains(r"MM$")) .then(1.0) .when(pl.col("col2").str.contains(r"K$|k$")) .then(0.001) .default(0.0) ).alias("col2") ) print(result)
输出结果
两种方案都能得到预期输出:
shape: (10, 2) ┌──────┬───────┐ │ col1 ┆ col2 │ │ --- ┆ --- │ │ str ┆ f32 │ ╞══════╪═══════╡ │ a ┆ 0.5 │ │ b ┆ 1.0 │ │ c ┆ 0.025 │ │ d ┆ 2.5 │ │ e ┆ 2.0 │ │ f ┆ 0.6 │ │ g ┆ 0.8 │ │ h ┆ 1.5 │ │ i ┆ 5.0 │ │ j ┆ 0.35 │ └──────┴───────┘
内容的提问来源于stack exchange,提问作者Victor Reial
相关产品推荐
相关产品推荐

