polars.Expr.map_elements
-
Применяет пользовательскую функцию (UDF) к каждому элементу столбца.
Предупреждение
Этот метод намного медленнее API нативных выражений. Используйте его только в том случае, если не можете реализовать логику другим способом.
Предположим, что функция:
x ↦ sqrt(x):- Для преобразования элементов серии рассмотрите:
pl.col("col_name").sqrt(). - Для преобразования внутренних элементов списков рассмотрите:
pl.col("col_name").list.eval(pl.element().sqrt()). - Для преобразования элементов полей структуры рассмотрите:
pl.col("col_name").struct.field("field_name").sqrt().
Если вы хотите заменить исходный столбец или поле, рассмотрите
.with_columnsи.with_fields.- Параметры:
-
- function
-
Лямбда-функция/функция для применения.
- return_dtype
-
Тип данных выходной серии.
По возможности рекомендуется задавать это значение. Если оно
None, тип данных определяется путём вызова функции с фиктивными данными и проверки результата. - skip_nulls
-
Не применять функцию к значениям, содержащим null (это быстрее).
- pass_name
-
Передавать имя серии пользовательской функции (это требует больше ресурсов).
- returns_scalar
-
Устарело с версии 1.32.0: Игнорируется и будет удалено в версии 2.0.
-
strategy{‘thread_local’, ‘threading’} -
Используемая стратегия многопоточности.
- ‘thread_local’: выполнять функцию Python в одном потоке.
- ‘threading’: выполнять функцию Python в отдельных потоках. Используйте с осторожностью, так как это может снизить производительность. Ускорение возможно только в том случае, если объём работы для каждого элемента значителен, а функция Python освобождает GIL (например, при вызове функции на C).
Предупреждение
Эта функциональность считается нестабильной. Она может быть изменена в любой момент без объявления таких изменений нарушающими совместимость.
Примечания
- Настоятельно не рекомендуется использовать
map_elements, так как фактически это означает выполнение циклов Python «for», что будет очень медленно. Для достижения наилучшей производительности по возможности используйте API нативных выражений. - Если ваша функция ресурсоёмкая и вы не хотите, чтобы она вызывалась более одного раза для заданных входных данных, рассмотрите возможность применения к ней декоратора
@lru_cache. Если ваши данные подходят для этого, можно добиться значительного ускорения. - Применение оконной функции с использованием
overв этом случае считается контекстом GroupBy, поэтому для применения функций к оконным группам можно использоватьmap_elements. - UDF, переданная в
map_elements, должна быть чистой, то есть не должна изменять состояние и зависеть от состояния, отличного от её аргументов. Polars может вызывать функцию с произвольными входными данными.
Примеры
>>> df = pl.DataFrame( ... { ... "a": [1, 2, 3, 1], ... "b": ["a", "b", "c", "c"], ... } ... )Функция применяется к каждому элементу столбца
'a':>>> df.with_columns( ... pl.col("a") ... .map_elements(lambda x: x * 2, return_dtype=pl.self_dtype()) ... .alias("a_times_2"), ... ) shape: (4, 3) ┌─────┬─────┬───────────┐ │ a ┆ b ┆ a_times_2 │ │ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ i64 │ ╞═════╪═════╪═══════════╡ │ 1 ┆ a ┆ 2 │ │ 2 ┆ b ┆ 4 │ │ 3 ┆ c ┆ 6 │ │ 1 ┆ c ┆ 2 │ └─────┴─────┴───────────┘Совет: лучше реализовать это с помощью выражения:
>>> df.with_columns( ... (pl.col("a") * 2).alias("a_times_2"), ... )>>> ( ... df.lazy() ... .group_by("b") ... .agg( ... pl.col("a") ... .implode() ... .map_elements(lambda x: x.sum(), return_dtype=pl.Int64) ... ) ... .collect() ... ) shape: (3, 2) ┌─────┬─────┐ │ b ┆ a │ │ --- ┆ --- │ │ str ┆ i64 │ ╞═════╪═════╡ │ a ┆ 1 │ │ b ┆ 2 │ │ c ┆ 4 │ └─────┴─────┘Совет: и здесь лучше реализовать это с помощью выражения:
>>> ( ... df.lazy() ... .group_by("b", maintain_order=True) ... .agg(pl.col("a").sum()) ... .collect() ... )Применение оконной функции с использованием
overбудет вести себя как контекст GroupBy: функция будет получать отдельные оконные группы:>>> df = pl.DataFrame( ... { ... "key": ["x", "x", "y", "x", "y", "z"], ... "val": [1, 1, 1, 1, 1, 1], ... } ... ) >>> df.with_columns( ... scaled=pl.col("val") ... .implode() ... .map_elements(lambda s: s * len(s), return_dtype=pl.List(pl.Int64)) ... .explode(empty_as_null=False) ... .over("key"), ... ).sort("key") shape: (6, 3) ┌─────┬─────┬────────┐ │ key ┆ val ┆ scaled │ │ --- ┆ --- ┆ --- │ │ str ┆ i64 ┆ i64 │ ╞═════╪═════╪════════╡ │ x ┆ 1 ┆ 3 │ │ x ┆ 1 ┆ 3 │ │ x ┆ 1 ┆ 3 │ │ y ┆ 1 ┆ 2 │ │ y ┆ 1 ┆ 2 │ │ z ┆ 1 ┆ 1 │ └─────┴─────┴────────┘Обратите внимание, что эту функцию также лучше реализовать нативными средствами:
>>> df.with_columns( ... scaled=(pl.col("val") * pl.col("val").count()).over("key"), ... ).sort("key") - Для преобразования элементов серии рассмотрите:
Expr.map_elements(
function: Callable[[Any],
Any],
return_dtype: PolarsDataType | DataTypeExpr | None = None,
*,
skip_nulls: bool = True,
pass_name: bool = False,
strategy: MapElementsStrategy = 'thread_local',
returns_scalar: bool = False,
) → Expr
© 2020 Ritchie Vink
© 2022 Polars contributors
Licensed under the MIT License.
https://docs.pola.rs/api/python/stable/reference/expressions/api/polars.Expr.map_elements.html