A DataFrame with grouping attached, waiting for agg/2.
Spark has no group_by relation: Aggregate is a single node holding the group type, the
grouping expressions and the aggregates, so groupBy(...).agg(...) is a client-side fiction
in every Spark client. This struct is where Latu keeps that half-built state, and it is inert
data like everything else.
Summary
Functions
Apply aggregates, giving a DataFrame back.
Rows per group, in a column called count.
Pivot the grouped frame on a column, turning its values into columns.
Types
@type t() :: %Latu.GroupedData{ grouping_sets: [[term()]], groupings: [Latu.Plan.expression()], input: Latu.DataFrame.t(), pivot: String.t() | atom() | nil, pivot_values: [term()], type: :group_by | :rollup | :cube | :pivot | :grouping_sets }
Functions
@spec agg(t(), term()) :: Latu.DataFrame.t()
Apply aggregates, giving a DataFrame back.
df |> Latu.group_by(:suburb) |> Latu.agg(total: F.sum(:price), n: F.count(:id))Takes the mixed list Latu.select/2 takes: trailing keywords name their expressions.
@spec count(t()) :: Latu.DataFrame.t()
Rows per group, in a column called count.
PySpark's GroupedData.count(), which is count(1) under that alias — reproduced, so the
output column matches.
Pivot the grouped frame on a column, turning its values into columns.
df |> Latu.group_by(:suburb) |> Latu.pivot(:year) |> Latu.agg(total: F.sum(:price))
df |> Latu.group_by(:suburb) |> Latu.pivot(:year, [2025, 2026]) |> Latu.count()Without values Spark runs a separate query first to find the distinct ones, so pass them
when you know them. Only a grouped frame can be pivoted, as in PySpark.