Рассмотрим следующий пример игрушки:
import polars as pl
pl.Config(tbl_rows=-1)
df = pl.DataFrame({"group": ["A", "A", "A", "B", "B"], "value": [1, 2, 3, 4, 5]})
print(df)
shape: (5, 2)
┌───────┬───────┐
│ group ┆ value │
│ --- ┆ --- │
│ str ┆ i64 │
╞═══════╪═══════╡
│ A ┆ 1 │
│ A ┆ 2 │
│ A ┆ 3 │
│ B ┆ 4 │
│ B ┆ 5 │
└───────┴───────┘
Далее у меня есть список значений индикатора, например vals=[10, 20, 30]
.
Я ищу эффективный способ вставить каждое из этих значений в новый столбец с именем ìndicator
, используя pl.lit()
, одновременно расширяя фрейм данных по вертикали таким образом, чтобы все существующие строки повторялись для каждого нового элемента в vals
.
Мое текущее решение — вставить новый столбец в df
, добавить его в список и впоследствии выполнить pl.concat
.
lit_vals = [10, 20, 30]
print(pl.concat([df.with_columns(indicator=pl.lit(val)) for val in lit_vals]))
shape: (15, 3)
┌───────┬───────┬───────────┐
│ group ┆ value ┆ indicator │
│ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i32 │
╞═══════╪═══════╪═══════════╡
│ A ┆ 1 ┆ 10 │
│ A ┆ 2 ┆ 10 │
│ A ┆ 3 ┆ 10 │
│ B ┆ 4 ┆ 10 │
│ B ┆ 5 ┆ 10 │
│ A ┆ 1 ┆ 20 │
│ A ┆ 2 ┆ 20 │
│ A ┆ 3 ┆ 20 │
│ B ┆ 4 ┆ 20 │
│ B ┆ 5 ┆ 20 │
│ A ┆ 1 ┆ 30 │
│ A ┆ 2 ┆ 30 │
│ A ┆ 3 ┆ 30 │
│ B ┆ 4 ┆ 30 │
│ B ┆ 5 ┆ 30 │
└───────┴───────┴───────────┘
Поскольку df
потенциально может иметь довольно много строк и столбцов, мне интересно, эффективно ли мое решение с точки зрения скорости и распределения памяти?
Просто для моего понимания: если я добавлю новый pl.DataFrame
в список, будет ли этот фрейм данных использовать дополнительную память или просто будут созданы новые указатели, которые ссылаются на фрагменты памяти, содержащие данные оригинала df
?
Вы можете добавить его в виде списка, а затем взорвать():
(
df
.with_columns(indicator=lit_vals)
.explode("indicator")
)
┌───────┬───────┬───────────┐
│ group ┆ value ┆ indicator │
│ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i64 │
╞═══════╪═══════╪═══════════╡
│ A ┆ 1 ┆ 10 │
│ A ┆ 1 ┆ 20 │
│ A ┆ 1 ┆ 30 │
│ A ┆ 2 ┆ 10 │
│ A ┆ 2 ┆ 20 │
│ A ┆ 2 ┆ 30 │
│ A ┆ 3 ┆ 10 │
│ A ┆ 3 ┆ 20 │
│ A ┆ 3 ┆ 30 │
│ B ┆ 4 ┆ 10 │
│ B ┆ 4 ┆ 20 │
│ B ┆ 4 ┆ 30 │
│ B ┆ 5 ┆ 10 │
│ B ┆ 5 ┆ 20 │
│ B ┆ 5 ┆ 30 │
└───────┴───────┴───────────┘
Вы можете назначить его как столбец и .explode()
df.with_columns(indicator=vals).explode("indicator")
shape: (15, 3)
┌───────┬───────┬───────────┐
│ group ┆ value ┆ indicator │
│ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ i64 │
╞═══════╪═══════╪═══════════╡
│ A ┆ 1 ┆ 10 │
│ A ┆ 1 ┆ 20 │
│ A ┆ 1 ┆ 30 │
│ A ┆ 2 ┆ 10 │
│ A ┆ 2 ┆ 20 │
│ … ┆ … ┆ … │
│ B ┆ 4 ┆ 20 │
│ B ┆ 4 ┆ 30 │
│ B ┆ 5 ┆ 10 │
│ B ┆ 5 ┆ 20 │
│ B ┆ 5 ┆ 30 │
└───────┴───────┴───────────┘
Чтобы указать dtype, вы можете использовать pl.lit()
(df.with_columns(indicator=pl.lit(vals, dtype=pl.List(pl.UInt8)))
.explode("indicator")
)
shape: (15, 3)
┌───────┬───────┬───────────┐
│ group ┆ value ┆ indicator │
│ --- ┆ --- ┆ --- │
│ str ┆ i64 ┆ u8 │
╞═══════╪═══════╪═══════════╡
│ A ┆ 1 ┆ 10 │
│ A ┆ 1 ┆ 20 │
│ A ┆ 1 ┆ 30 │
│ A ┆ 2 ┆ 10 │
│ A ┆ 2 ┆ 20 │
│ … ┆ … ┆ … │
│ B ┆ 4 ┆ 20 │
│ B ┆ 4 ┆ 30 │
│ B ┆ 5 ┆ 10 │
│ B ┆ 5 ┆ 20 │
│ B ┆ 5 ┆ 30 │
└───────┴───────┴───────────┘
Вы имеете в виду лайк indicator=pl.lit(vals, dtype=pl.List(pl.UInt8))
?
Да, dtype отдельных элементов vals
должен быть pl.Uint8
. Его можно использовать после explode
. Мне просто интересно, смогу ли я сделать это при назначении нового столбца?
df.with_columns(indicator=pl.lit(vals, dtype=pl.List(pl.UInt8))).explode(...)
должен это сделать.
Вы правы! Спасибо
Можно ли напрямую привести элементы
vals
кpl.Uint8
?