Spec-Zone.ru › Polars

polars.Expr.map_elements

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

Применяет пользовательскую функцию (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")  

© 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API