如何在Polars中高效实现DataFrame行与单行DataFrame的除法?
Polars实现DataFrame与单行DataFrame的高效除法运算
需求描述
需要将Polars DataFrame的每一行与一个单行DataFrame执行除法运算,类似Pandas中的df.divide方法。当前通过重复单行DataFrame至原DataFrame行数再运算的方式,在数据量较大时耗时严重,需要更优实现。
当前低效实现
from itertools import repeat import polars as pl data = {'a': [i for i in range(1, 5)], 'b': [i for i in range(1, 5)], 'c': [i for i in range(1, 5)], 'd': [i for i in range(1, 5)]} df = pl.DataFrame(data) divisors = pl.DataFrame({'d1': 1, 'd2': 10, 'd3': 100, 'd4': 1000}) divisors_as_big_as_df = pl.concat([item for item in repeat(divisors, len(df))]) divided_df = df / divisors_as_big_as_df
优化方案
方案1:利用Polars自动广播特性(推荐)
Polars支持单行DataFrame与多行DataFrame的自动广播运算,无需手动复制数据。只需确保两个DataFrame的列名一一对应:
import polars as pl data = {'a': list(range(1,5)), 'b': list(range(1,5)), 'c': list(range(1,5)), 'd': list(range(1,5))} df = pl.DataFrame(data) # 调整除数DataFrame的列名与原DataFrame一致 divisors = pl.DataFrame({'a': 1, 'b': 10, 'c': 100, 'd': 1000}) # 直接执行除法,Polars自动广播单行数据至原行数 divided_df = df / divisors
方案2:保留原列名,通过表达式指定对应除数
如果不想修改除数DataFrame的列名,可以提取单行的数值作为常量,结合列表达式批量运算:
import polars as pl data = {'a': list(range(1,5)), 'b': list(range(1,5)), 'c': list(range(1,5)), 'd': list(range(1,5))} df = pl.DataFrame(data) divisors = pl.DataFrame({'d1': 1, 'd2': 10, 'd3': 100, 'd4': 1000}) # 提取单行除数的数值列表 div_values = divisors.row(0) # 逐个列指定除法运算 divided_df = df.select( pl.col('a') / div_values[0], pl.col('b') / div_values[1], pl.col('c') / div_values[2], pl.col('d') / div_values[3] )
方案3:批量生成表达式(简洁版)
通过列表推导式自动匹配列与对应除数,适合列数较多的场景:
divided_df = df.select( [pl.col(col) / divisors.row(0)[idx] for idx, col in enumerate(df.columns)] )
优化原理
手动复制单行DataFrame会生成大量冗余数据,占用内存且增加IO开销。而Polars的广播机制是逻辑层面的重复,不会实际复制数据,运算时直接将单行数值应用到每一行,效率提升显著。
内容的提问来源于stack exchange,提问作者Lasse
相关产品推荐
相关产品推荐

