在数据分析工作中,我们经常会遇到这样一种情况:从业务系统导出的CSV或日志文件中,某一列本来应该是数值,却被存成了用逗号、竖线等符号拼接的字符串,例如"12,34,56"。如果直接用Polars做数学运算,这一列会被当成文本,导致报错或者结果错误。要解决这个问题,就必须先把字符串列拆分成列表,再把列表里的每个元素转换成整数类型。Polars的表达式API让这件事变得非常直观,而且性能远好于用Python循环逐行处理。
一、用str.split把字符串列转为列表
Polars的str.split方法可以按照指定的分隔符,将每个字符串切分成一个字符串组成的列表。这一步是整个转换的基础,拆分后原本的一列文本就变成了结构体列表列,每一个单元格都是一个List[str]类型。我们需要特别注意分隔符参数必须和实际数据完全一致,否则会出现空列表或者拆分错误。
下面是一段最简单的示例代码,演示如何读取数据并完成拆分:
import polars as pl
# 构造示例数据,code列是逗号分隔的字符串
df = pl.DataFrame({
"id": [1, 2, 3],
"code": ["12,34,56", "7,8", "100,200,300"]
})
# 使用str.split拆分成列表
df_split = df.with_columns(
pl.col("code").str.split(",").alias("code_list")
)
print(df_split)
运行后,code_list列的每个值都变成了类似["12", "34", "56"]这样的字符串列表。此时虽然已经是列表结构,但内部元素仍为字符串,无法直接参与整数运算。如果原始数据里偶尔出现空字符串或者多余空格,可以在split之前先用str.strip_chars做清理,提升后续转换的稳定性。
二、将列表内的字符串转换为整数
拆分完成后,下一步就是把列表中的每一个字符串元素转成整数。Polars提供了arr.eval方法,它能在列表内部执行表达式,结合cast即可完成类型转换。这种做法比先explode再group再拼接要简洁得多,也避免了中间产生巨大的展开表。
我们接着上面的df_split继续操作:
# 将列表里的每个字符串转为整数
df_int = df_split.with_columns(
pl.col("code_list").arr.eval(
pl.element().cast(pl.Int64)
).alias("code_int_list")
)
print(df_int)
此时code_int_list列的值已经变成[12, 34, 56]这样的整数列表。如果某些单元格里混入了非数字文本,比如"12,abc",cast操作会直接抛出异常。因此在生产环境里,建议先用str.contains做一层过滤,或者用fill_null处理空值,保证转换的健壮性。
三、根据业务需要展开或保留列表
转换成整数列表之后,不同场景对数据形态的要求不一样。如果你希望每个数字占一行,就用explode把列表展开;如果下游模型只接受定长向量,那么保留列表反而更合适。Polars对这两种用法都支持得很好,而且懒执行模式下会自动优化执行计划。
以下代码展示如何展开成多行,以及不做展开直接使用的对比:
# 展开成多行,每个数字一行
df_exploded = df_int.explode("code_int_list").rename({"code_int_list": "code_int"})
print(df_exploded)
# 如果不展开,直接对列表求和
df_sum = df_int.with_columns(
pl.col("code_int_list").arr.sum().alias("code_sum")
)
print(df_sum)
展开后的表适合做明细统计,比如算每个id下数字的分布;而保留列表并调用arr.sum、arr.mean则适合做聚合特征。两者在Polars里都能用声明式写法完成,不需要手写循环,代码可读性和运行效率都更高。
四、完整链式写法与性能建议
实际项目中,我们通常会把上述步骤写成一条链式表达式,既清晰又方便维护。同时,当数据量很大时,建议使用懒模式pl.LazyFrame,让Polars在后台做谓词下推和内存复用,进一步降低资源消耗。
下面是一个整合了清洗、拆分、转换、聚合的完整示例:
import polars as pl
lf = pl.LazyFrame({
"id": [1, 2, 3],
"code": ["12,34,56", "7, 8", "100,200,300"]
})
result = (
lf.with_columns(
pl.col("code").str.strip_chars().str.split(",").alias("code_list")
)
.with_columns(
pl.col("code_list").arr.eval(pl.element().cast(pl.Int64)).alias("code_int_list")
)
.with_columns(
pl.col("code_int_list").arr.sum().alias("total")
)
.collect()
)
print(result)
这段代码先用strip_chars去掉可能的空格,再拆分、转整数、求和,全程没有Python层循环。在百万行级别的数据上,Polars通常比同等逻辑的Pandas实现快数倍,且内存峰值更低。如果你的字符串列还可能包含空值,只需在split前加一句pl.col("code").fill_null("")即可避免报错。掌握这种字符串到整数列表的转换套路,能覆盖大部分日志解析和特征工程的类似需求。