Aggregate & Array Functions

Spark tutorial · PySpark.in

Aggregate Functions: groupBy, count, avg, sum, min, max

Overview: Aggregation is a fundamental operation for data analysis – summarizing data by groups. PySpark DataFrames support aggregation through the groupBy() method and a suite of aggregate functions like count, sum, avg (average), min, max, and more. The typical pattern is: group the DataFrame by one or more keys, then apply aggregation(s) to each group. The result is a new DataFrame representing the summary for each group.

Typical Use Cases:

Spark's groupBy returns a special GroupedData object on which you can call aggregate functions or the .agg() method to specify multiple aggregates. Common aggregation functions include count() (row count), sum() for totals, avg() for mean, min() and max() for extrema. Let's see these in action with a sales dataset.

Suppose we have a simple DataFrame of product sales, with columns for region, product, and revenue (sales amount):

Counting and Grouping

The most basic aggregation is counting rows in each group.

Example 1: Count sales records per region.

PYTHON
1from pyspark.sql.functions import count
2from pyspark.sql import SparkSession
3spark = SparkSession.builder.appName("BuiltInFuncDemo").getOrCreate()
4sales_data = [
5 ("East", "Book", 1200),
6 ("East", "Pen", 300),
7 ("East", "Book", 600),
8 ("West", "Pen", 400),
9 ("West", "Book", 500)
10]
11sales_cols = ["region", "product", "amount"]
12df_sales = spark.createDataFrame(sales_data, sales_cols)
13df_sales.groupBy("region").agg(count("*").alias("count")).show()
▶ Output will appear here.

This tells us there were 3 sales records in the East region and 2 in the West region. We used count("*") which counts all rows; you could also use count("amount") (or any column) since none are null in this dataset. Alternatively, PySpark allows a shorthand df_sales.groupBy("region").count() which produces the same result with a default "count" column.

Sum, Average, Min, Max

Often, we want more than just counts. We can compute multiple aggregates in one go using the .agg() method and passing a list of aggregate expressions.

Example 2: Multiple aggregates – total sales, average sale, min and max sale per region.

PYTHON
1from pyspark.sql.functions import sum, avg, min, max
2from pyspark.sql.functions import count
3from pyspark.sql import SparkSession
4spark = SparkSession.builder.appName("BuiltInFuncDemo").getOrCreate()
5sales_data = [
6 ("East", "Book", 1200),
7 ("East", "Pen", 300),
8 ("East", "Book", 600),
9 ("West", "Pen", 400),
10 ("West", "Book", 500)
11]
12sales_cols = ["region", "product", "amount"]
13df_sales = spark.createDataFrame(sales_data, sales_cols)
14df_sales.groupBy("region").agg(
15 sum("amount").alias("total_sales"),
16 avg("amount").alias("avg_sales"),
17 min("amount").alias("min_sales"),
18 max("amount").alias("max_sales")
19).show()
▶ Output will appear here.

Let's interpret this:

The average appears with a decimal (700.0 and 450.0) because Spark's avg returns a double type. If needed, we could format or round it, but here it's fine.

We see clearly that the East region had higher total sales and a higher max single sale, whereas the West had fewer and smaller sales. This kind of multi-aggregation query is very powerful for summarizing data in one pass.

Note: The groupBy("region").agg(...) pattern is used to compute multiple aggregates at once. If you only need one aggregate, you can use shortcuts like groupBy().sum("amount"), groupBy().avg("amount"), etc., which produce columns like sum(amount). Using alias() helps rename them to something friendlier as we did.

Grouping by Multiple Columns

You can group by more than one column if you need a finer breakdown. For example, df_sales.groupBy("region", "product").sum("amount") would give total sales per (region, product) pair. This is similar to SQL grouping on multiple fields. For brevity, we'll not show a full example output here, but it's straightforward: each unique combination of region and product becomes a group.

Best Practices and Notes on Aggregation:

Use Case Example: In a business context, you might group sales data by region and quarter to see how different areas perform over time, or group user data by subscription_plan to compute average revenue per plan. Aggregation functions help turn raw data into insights like "Sales in East region totaled 2100, averaging 700 per order, with a maximum single sale of 1200".

Spark provides many more aggregate functions (e.g., mean alias for avg, stddev for standard deviation, collect_list to gather all items in a group, etc.), but count, sum, avg, min, max are the most frequently used. These functions, when used via PySpark's DataFrame API, are optimized and will run in parallel across your cluster.

Working with Array Columns: explode, array_contains, size

Overview: Modern data often includes arrays or lists (e.g., a list of tags, a list of purchased items, etc.). PySpark has functions to manipulate array-type columns. Here we discuss:

These functions make it easier to work with nested data structures like JSON arrays or lists that come from data sources.

Typical Use Cases:

Let's use a concrete example. Consider an orders DataFrame where each order has an array of items purchased:

PYTHON
1from pyspark.sql import SparkSession
2spark = SparkSession.builder.appName("BuiltInFuncDemo").getOrCreate()
3orders_data = [
4 (1001, ["Laptop", "Mouse", "Cable"]),
5 (1002, ["Monitor"]),
6 (1003, ["Mouse", "Cable"]),
7 (1004, ["Laptop", "Monitor"])
8]
9orders_cols = ["order_id", "items"]
10df_orders = spark.createDataFrame(orders_data, orders_cols)
11df_orders.show()
▶ Output will appear here.

(The items array is shown truncated above for display; the actual arrays are as defined in the data.) Each order has an array of product names in the items column.

Using explode() to Unnest Arrays

The explode(array_col) function will take each element of the array and turn it into its own row. Other columns are duplicated accordingly. This is extremely useful to normalize data for analysis – for example, counting how many times each product was sold, or simply to filter at the item level.

Example: Explode orders into individual items.

PYTHON
1from pyspark.sql.functions import explode,col
2from pyspark.sql import SparkSession
3spark = SparkSession.builder.appName("BuiltInFuncDemo").getOrCreate()
4orders_data = [
5 (1001, ["Laptop", "Mouse", "Cable"]),
6 (1002, ["Monitor"]),
7 (1003, ["Mouse", "Cable"]),
8 (1004, ["Laptop", "Monitor"])
9]
10orders_cols = ["order_id", "items"]
11df_orders = spark.createDataFrame(orders_data, orders_cols)
12df_items = df_orders.select("order_id", explode(col("items")).alias("item"))
13df_items.show()
▶ Output will appear here.

Now each (order_id, item) is a separate row. Order 1001, which originally had 3 items, now appears as 3 rows (1001, Laptop), (1001, Mouse), (1001, Cable). This flattened view can be aggregated or filtered easily. For instance, we could now group by "item" to count total sales of each product.

Notice that the explode operation creates a new column (item in this case) for each element of the array. If an array is empty, explode will produce no rows for that entry (it essentially removes that row in the exploded result). If the array is null, Spark's explode will produce null output (you might consider using explode_outer if you want to keep those and get nulls).

Using array_contains() to Check for Membership

The array_contains(col, value) function returns a boolean: True if the array contains the specified value, False otherwise. We can use this to filter rows or create a flag column.

Example: Flag orders that include a "Laptop".

PYTHON
1from pyspark.sql.functions import array_contains
2from pyspark.sql import SparkSession
3spark = SparkSession.builder.appName("BuiltInFuncDemo").getOrCreate()
4orders_data = [
5 (1001, ["Laptop", "Mouse", "Cable"]),
6 (1002, ["Monitor"]),
7 (1003, ["Mouse", "Cable"]),
8 (1004, ["Laptop", "Monitor"])
9]
10orders_cols = ["order_id", "items"]
11df_orders = spark.createDataFrame(orders_data, orders_cols)
12df_orders_flag = df_orders.withColumn("has_laptop", array_contains(col("items"), "Laptop"))
13df_orders_flag.select("order_id", "items", "has_laptop").show()
▶ Output will appear here.

We added a boolean column has_laptop that is true for orders 1001 and 1004 (since their item lists contain "Laptop"), and false for the others. This is very handy for filtering: for example, df_orders.filter(array_contains(col("items"), "Laptop")) would give only orders that included a laptop. Under the hood, this is a distributed operation that checks each element of the array for the match.

Note: array_contains returns NULL if the array itself is null. In our data there's no null array, so we get straightforward booleans. If there were a possibility of null, you might combine with a coalesce or handle nulls accordingly.

Using size() to Get Array Length

The size(array_col) function returns an integer equal to the number of elements in the array (0 for an empty array). This can be used to know how many items are in each order, how many skills a person has, etc.

Example: Count number of items in each order.

PYTHON
1from pyspark.sql import SparkSession
2from pyspark.sql.functions import size
3spark = SparkSession.builder.appName("BuiltInFuncDemo").getOrCreate()
4orders_data = [
5 (1001, ["Laptop", "Mouse", "Cable"]),
6 (1002, ["Monitor"]),
7 (1003, ["Mouse", "Cable"]),
8 (1004, ["Laptop", "Monitor"])
9]
10orders_cols = ["order_id", "items"]
11df_orders = spark.createDataFrame(orders_data, orders_cols)
12df_orders.select("order_id", size(col("items")).alias("num_items")).show()
▶ Output will appear here.

We can see order 1001 had 3 items, order 1002 had 1, etc. This kind of information could be used in further analysis, e.g., to compute the average number of items per order or to find orders that might be bulk purchases (many items).

Best Practices with Arrays:

By using array functions, we can easily manage data that has a one-to-many relationship embedded in a single row. Flattening with explode and then aggregating or filtering gives us flexibility to analyze nested data structures.

More Spark tutorials

All tutorials · Try the free PySpark compiler · Practice challenges