prepend

prepend(expr, offset=1, *, prepend_expr=None)

Returns a Polars expression that prepends rows using the prepend_expr= parameter.

If prepend_expr= is not provided, the first row(s) of the current DataFrame—or Series if used within the list namespace—will be used by default, based on the offset= value.

ImportantUnconventional Operation

prepend() is an unconventional operation in Polars. In most cases, similar behavior can be achieved using expr1.append(expr2), or through pl.concat(), pl.DataFrame.vstack(), or pl.DataFrame.extend().

However, it provides a convenient way to insert elements quickly when working within the list namespace.

Keep in mind that prepend() dynamically depends on the total number of rows, which sets the upper limit on how many rows can be prepended. If offset= exceeds the current row count, the result may resemble a duplication of the original column.

To prepend more rows than the total number of existing rows, you currently need to call prepend() multiple times manually.

You may consider rechunking the result of prepend() using pl.Expr.rechunk() for better performance.

Parameters

expr : pl.Expr

A Polars expression to which rows will be prepended.

offset : int = 1

Number of rows to prepend. Must be a positive integer.

prepend_expr : pl.Expr | None = None

The expression to prepend.

Returns

: pl.Expr

A Polars expression with the specified values prepended.

Examples

DataFrame Context

Because prepend() modifies the total number of rows, it cannot be used inside with_columns().

Prepend one row using the default behavior:

import polars as pl
import turtle_island as ti

pl.Config.set_fmt_table_cell_list_len(10)
df = pl.DataFrame({"x": [1, 2, 3, 4], "y": [5, 6, 7, 8]})
df.select(ti.prepend(pl.all()))
shape: (5, 2)
xy
i64i64
15
15
26
37
48

Prepend two rows using a literal value:

df.select(
    ti.prepend(pl.all(), offset=2, prepend_expr=pl.lit(0))
)
shape: (6, 2)
xy
i64i64
00
00
15
26
37
48

Prepend two rows using a custom expression:

df.select(
    ti.prepend(pl.all(), offset=3, prepend_expr=pl.col("x").mul(pl.col("y")))
)
shape: (7, 2)
xy
i64i64
55
1212
2121
15
26
37
48

List Namespace Context

In the list namespace, it may be easier to think of each row as an element in a list. Conceptually, you’re working with a pl.Series, where each row corresponds to one item in the list.

Prepend one element to each list:

df2 = pl.DataFrame(
    {
        "x": [[1, 2, 3, 4], [5, 6, 7, 8]],
        "y": [[9, 10, 11, 12], [13, 14, 15, 16]],
    }
)
df2.select(pl.all().list.eval(ti.prepend(pl.element())))
shape: (2, 2)
xy
list[i64]list[i64]
[1, 1, 2, 3, 4][9, 9, 10, 11, 12]
[5, 5, 6, 7, 8][13, 13, 14, 15, 16]

Prepend two elements using a literal value:

df2.select(
    pl.all().list.eval(
        ti.prepend(pl.element(), offset=2, prepend_expr=pl.lit(0))
    )
)
shape: (2, 2)
xy
list[i64]list[i64]
[0, 0, 1, 2, 3, 4][0, 0, 9, 10, 11, 12]
[0, 0, 5, 6, 7, 8][0, 0, 13, 14, 15, 16]

Prepend three elements using a custom expression:

df2.select(
    pl.all().list.eval(
        ti.prepend(pl.element(), offset=3, prepend_expr=pl.element().add(10))
    )
)
shape: (2, 2)
xy
list[i64]list[i64]
[11, 12, 13, 1, 2, 3, 4][19, 20, 21, 9, 10, 11, 12]
[15, 16, 17, 5, 6, 7, 8][23, 24, 25, 13, 14, 15, 16]

Prepend five elements using a literal value.

df2.select(
    pl.all()
    .list.eval(ti.prepend(pl.element(), offset=4, prepend_expr=pl.lit(0)))
    .list.eval(ti.prepend(pl.element(), offset=1, prepend_expr=pl.lit(0)))
)
shape: (2, 2)
xy
list[i64]list[i64]
[0, 0, 0, 0, 0, 1, 2, 3, 4][0, 0, 0, 0, 0, 9, 10, 11, 12]
[0, 0, 0, 0, 0, 5, 6, 7, 8][0, 0, 0, 0, 0, 13, 14, 15, 16]

In this case, the number of elements to prepend (5) exceeds the number of elements in each list (4), so you need to call prepend() twice in separate .list.eval() steps to achieve the desired result.

You can also approach this by using bulk_append() to achieve the same result:

df2.select(pl.all().list.eval(ti.bulk_append(pl.repeat(0, 5), pl.element())))
shape: (2, 2)
xy
list[i64]list[i64]
[0, 0, 0, 0, 0, 1, 2, 3, 4][0, 0, 0, 0, 0, 9, 10, 11, 12]
[0, 0, 0, 0, 0, 5, 6, 7, 8][0, 0, 0, 0, 0, 13, 14, 15, 16]
  1. If prepend_value= is an expression rather than a literal, there’s no reliable way to determine how many times the expression should be prepended dynamically.

  2. This approach only works within the list namespace. Aliases appear to have no effect in this context. For example, pl.repeat() typically carries a “literal” alias in the DataFrame context, which makes it difficult to programmatically substitute it with the original column name—especially when supporting wildcards like pl.all() or pl.col("*").