如何高效从多个稀疏Series创建类索引Polars DataFrame?
从稀疏Series创建带非连续整数主键的Polars DataFrame
需求:基于多个稀疏Series(形式为(index, value)元组或{index: value}映射),创建带有非连续整数主键的Polars DataFrame。
示例对比与现有尝试
Pandas实现方式
Pandas支持直接通过字典形式创建并排序索引:
>>> import pandas as pd >>> pd.DataFrame({ "A": {0: 'a', 20: 'b', 40: 'c'}, "B": {10: 'd', 20: 'e', 30: 'f'}, "C": {20: 'g', 30: 'h'} }).sort_index()
Polars现有尝试
由于Polars没有内置索引机制,需先将每个Series转换为包含index列的DataFrame:
import polars as pl A = pl.DataFrame({"index": [0, 20, 40], "A": ['a', 'b', 'c'] }) B = pl.DataFrame({"index": [10, 20, 30], "B": ['d', 'e', 'f'] }) C = pl.DataFrame({"index": [20, 30], "C": ['g', 'h'] })
之后通过多次全外连接得到结果:
>>> A.join(B, on='index', how='full', coalesce=True).join(C, on='index', how='full', coalesce=True).sort(by='index')
但这种方式存在两个问题:
- 列数较多时,多次join的写法繁琐且冗余
- 大数据场景下性能低于Pandas的直接创建方式(测试场景:30万行20列数据集)
更简洁高效的Polars实现方案
方案1:统一索引后批量构建列(适合字典形式输入)
通过先收集所有索引、再批量生成列的方式,避免多次join操作:
import polars as pl # 原始稀疏数据(字典形式) series_dict = { "A": {0: 'a', 20: 'b', 40: 'c'}, "B": {10: 'd', 20: 'e', 30: 'f'}, "C": {20: 'g', 30: 'h'} } # 1. 收集所有唯一索引并排序 all_indices = sorted({idx for s in series_dict.values() for idx in s.keys()}) # 2. 为每个列构建DataFrame,利用Polars向量化映射提升性能 dfs = [] for col_name, data in series_dict.items(): df = pl.DataFrame({ "index": all_indices, col_name: pl.Series(all_indices).map_dict(data, default=None) }) dfs.append(df) # 3. 横向拼接所有DataFrame(index列完全一致,直接hstack) result = pl.concat(dfs, how="horizontal").sort(by="index") print(result)
方案2:长格式转宽格式(适合元组列表形式输入)
如果输入是(index, value)元组列表,可通过纵向拼接后透视实现:
import polars as pl # 原始稀疏数据(元组列表形式) series_tuples = [ ("A", [(0, 'a'), (20, 'b'), (40, 'c')]), ("B", [(10, 'd'), (20, 'e'), (30, 'f')]), ("C", [(20, 'g'), (30, 'h')]) ] # 1. 转换为长格式DataFrame列表 long_dfs = [pl.DataFrame(tuples, schema=["index", col]) for col, tuples in series_tuples] # 2. 纵向拼接后透视成宽格式 long_df = pl.concat(long_dfs, how="vertical") result = long_df.pivot( index="index", values=[col for col, _ in series_tuples], aggregate_function="first" ).sort(by="index") print(result)
性能优化说明
- 避免多次全外连接:逐次join会重复处理数据,时间复杂度随列数增加呈线性上升;上述方案通过统一处理索引,将时间复杂度控制在O(N)(N为总数据量)。
- 利用Polars向量化操作:使用
pl.Series.map_dict替代Python列表推导,充分利用Polars的底层优化,减少Python层级的循环开销。 - 大数据场景优先选方案2:Polars的
pivot操作针对大规模数据做了专门优化,在30万行20列的测试场景下,性能显著优于多次join。
内容的提问来源于stack exchange,提问作者Jongwook Choi
相关产品推荐
相关产品推荐

