独立填充列

Fill columns independently

我有一个 python class 有两个数据 class,第一个是极地时间序列,第二个是字符串列表。

在字典中,提供了字符串和函数的映射,对于字符串的每个元素都关联了一个函数,该函数 returns 极坐标框架(一列)。

然后有一个函数 class 创建一个极坐标数据框,第一列是时间序列,其他列是用这个函数创建的。

列都是独立的。

有没有办法并行创建这个数据框?

这里我尝试定义一个最小的例子:

class data_frame_constr():
    function_list: List[str]
    time_series: pl.DataFrame

    def compute_indicator_matrix(self) -> pl.DataFrame:
        for element in self.function_list:
            self.time_series.with_column(
                [
                    mapping[element] # here is where we construct columns with the loop and mapping[element] is a custom function that returns a pl column
                ]
            )
        return self.time_series

例如,function_list = ["正方形", "square_root"].

Time frame 是列时间序列,我需要创建平方和平方根(或其他自定义复杂函数,由其名称标识)列,但我只在运行时知道函数列表,在构造函数中指定.

您可以使用 with_columns 上下文来提供表达式列表,只要表达式是独立的即可。 (注意复数形式:with_columns。)Polars 将尝试并行 运行 列表中的所有表达式,即使表达式列表是动态生成的run-time.


def mapping(func_str: str) -> pl.Expr:
    '''Generate Expression from function string'''
    ...


def compute_indicator_matrix(self) -> pl.DataFrame:
    expr_list = [mapping(next_funct_str)
                 for next_funct_str in self.function_list]
    self.time_series = self.time_series.with_columns(expr_list)
    return self.time_series

请注意:一个常见的误解是 Polars 是一个通用线程池,它将 运行 any/all 并行编码。这不是真的。

如果您的任何表达式调用外部库或自定义 Python 字节码函数(例如,使用 lambda 函数、mapapply 等...) ,那么您的代码将受制于 Python GIL,并且无论您如何编码,都将 运行 single-threaded - 。因此,尝试仅使用 Polars 表达式来实现您的目标(而不是调用外部库或 Python 函数。)

例如,尝试以下操作。 (选择一个 nbr_rows 的值,这会给您的计算平台带来压力。)如果我们 运行 下面的代码,它将 运行 并行,因为所有内容都是使用 Polars 表达式表示的,无需调用外部库或自定义 Python 代码。结果是 令人尴尬 的并行性能。

nbr_rows = 100_000_000
df = pl.DataFrame({
    'col1': pl.repeat(2, nbr_rows, eager=True),
})

df.with_columns([
    pl.col('col1').pow(1.1).alias('exp_1.1'),
    pl.col('col1').pow(1.2).alias('exp_1.2'),
    pl.col('col1').pow(1.3).alias('exp_1.3'),
    pl.col('col1').pow(1.4).alias('exp_1.4'),
    pl.col('col1').pow(1.5).alias('exp_1.5'),
])

但是,如果我们改为使用调用 Python 字节码的 lambda 函数编写代码,那么它将 运行 非常 缓慢。

import math
df.with_columns([
    pl.col('col1').apply(lambda x: math.pow(x, 1.1)).alias('exp_1.1'),
    pl.col('col1').apply(lambda x: math.pow(x, 1.2)).alias('exp_1.2'),
    pl.col('col1').apply(lambda x: math.pow(x, 1.3)).alias('exp_1.3'),
    pl.col('col1').apply(lambda x: math.pow(x, 1.4)).alias('exp_1.4'),
    pl.col('col1').apply(lambda x: math.pow(x, 1.5)).alias('exp_1.5'),
])