独立填充列
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
函数、map
、apply
等...) ,那么您的代码将受制于 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'),
])
我有一个 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
函数、map
、apply
等...) ,那么您的代码将受制于 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'),
])