2025, Dec 16 12:04

Выбор значений по индексам из другого столбца в Polars без циклов

Как в Polars выбрать значения из ref по позициям из столбца idx без циклов: вычитаем единицу для 0‑индексации и добавляем столбец через with_columns.

Когда нужно получить значения из одного столбца по позициям, записанным в другом столбце, возникает соблазн написать цикл. В Polars это делается в одну операцию — за счет прямой индексации Series и добавления результата как нового столбца.

Обзор задачи

Нужно создать новый столбец, чьи значения берутся из ref, а позиции — из idx. Значения в idx заданы в 1‑индексации, поэтому при обращении нужно учесть 0‑индексацию в Polars.

import polars as pl
tbl = pl.DataFrame({
    'ref': ['a', 'b', 'c', 'd', 'e', 'f'],
    'idx': [4, 3, 1, 6, 2, 5],
})

Что происходит под капотом

Series в Polars индексируются с нуля, а позиции в idx — с единицы. Если использовать idx как есть, каждая строка сместится на один. Правильный подход — вычесть единицу из idx перед индексацией Series ref.

Есть еще один важный момент. Прямая индексация Series вроде tbl['col'][...] относится к Eager‑API; в ленивом режиме (Lazy) она недоступна.

Решение

Добавьте вычисляемый столбец одним вызовом DataFrame.with_columns(). Единственная поправка — idx - 1, чтобы согласовать 0‑индексацию.

import polars as pl
tbl = pl.DataFrame({
    'ref': ['a', 'b', 'c', 'd', 'e', 'f'],
    'idx': [4, 3, 1, 6, 2, 5],
})
enriched = tbl.with_columns(**{'ref[idx]': tbl['ref'][tbl['idx'] - 1]})

Это создаст новый столбец ref[idx] со значениями ['d', 'c', 'a', 'f', 'b', 'e'], как и задумывалось.

Почему это важно

Понимание правил индексации в Polars помогает избежать «off‑by‑one» — незаметных ошибок на единицу в конвейерах обработки данных. Оно также проясняет различие между Eager и Lazy‑контекстами: индексация Series вроде tbl['ref'][...] работает в Eager, но не применима в Lazy. Такая ментальная модель экономит время при переключении между быстрыми интерактивными сессиями и оптимизированными пайплайнами.

Замечание о выводе

Если при печати DataFrame в интерактивной сессии вы видите аккуратную ASCII‑таблицу, это стандартный pretty print в IPython. Дополнительный код форматирования не нужен.

Итоги

Для динамических позиционных выборок между столбцами в Polars используйте DataFrame.with_columns() и приводите позиции к 0‑индексации, вычитая единицу, если входные данные 1‑индексные. Помните, что прямые операции над Series вроде tbl['col'][...] относятся к Eager‑API и недоступны в Lazy. С учетом этих деталей шаблон выражается просто и надежно.