Built with Tutify.io

    AIStudyLabs

    DataFrame - Pivot and Unpivot

    DataFrame - Pivot and Unpivot

    Introduction

    In PySpark, the pivot() function is used to pivot/rotate the data from one DataFrame column into multiple columns (transform row to column) and the inverse operation, unpivot, allows transforming it back (transform columns to rows).

    Pivot() is an aggregation where one of the grouping columns' values is transposed into individual columns with distinct data.

    Let’s create a DataFrame to work with.

    from pyspark.sql import SparkSession
    from pyspark.sql.functions import expr
    
    spark = SparkSession.builder.master("local").appName("PivotExample").getOrCreate()
    
    data = [
        ("Banana", 1000, "USA"),
        ("Carrots", 1500, "USA"),
        ("Beans", 1600, "USA"),
        ("Orange", 2000, "USA"),
        ("Orange", 2000, "USA"),
        ("Banana", 400, "China"),
        ("Carrots", 1200, "China"),
        ("Beans", 1500, "China"),
        ("Orange", 4000, "China"),
        ("Banana", 2000, "Canada"),
        ("Carrots", 2000, "Canada"),
        ("Beans", 2000, "Mexico")
    ]
    
    columns = ["Product", "Amount", "Country"]
    df = spark.createDataFrame(data, columns)
    df.show()
    

    DataFrame ‘df’ consists of 3 columns: Product, Amount, and Country, as shown below.

    +-------+------+-------+
    |Product|Amount|Country|
    +-------+------+-------+
    | Banana|  1000|    USA|
    |Carrots|  1500|    USA|
    |  Beans|  1600|    USA|
    | Orange|  2000|    USA|
    | Orange|  2000|    USA|
    | Banana|   400|  China|
    |Carrots|  1200|  China|
    |  Beans|  1500|  China|
    | Orange|  4000|  China|
    | Banana|  2000| Canada|
    |Carrots|  2000| Canada|
    |  Beans|  2000| Mexico|
    +-------+------+-------+
    

    1. Pivot PySpark DataFrame

    pivot() is an aggregation where one of the grouping columns' values is transposed into individual columns with distinct data. From the above DataFrame, to get the total amount exported to each country of each product, we can group by Product, pivot by Country, and sum the Amount.

    pivot_df = df.groupBy("Product").pivot("Country").sum("Amount")
    pivot_df.show()
    

    This will transpose the countries from DataFrame rows into columns and produce the output below. Wherever data is not present, it is represented as null by default.

    +-------+------+-----+------+----+
    |Product|Canada|China|Mexico| USA|
    +-------+------+-----+------+----+
    | Orange|  null| 4000|  null|4000|
    |  Beans|  null| 1500|  2000|1600|
    | Banana|  2000|  400|  null|1000|
    |Carrots|  2000| 1200|  null|1500|
    +-------+------+-----+------+----+
    

    2. Pivot Performance Improvement in Spark 2.0

    From Spark 2.0 onwards, performance has been improved for Pivot; however, if you are using a lower version, note that Pivot is a very expensive operation. It is recommended to provide column data (if known) as an argument to the function as shown below.

    countries = ["USA", "China", "Canada", "Mexico"]
    pivot_df = df.groupBy("Product").pivot("Country", countries).sum("Amount")
    pivot_df.show()
    

    Another approach is to use two-phase aggregation. Spark 2.0 uses this implementation to improve performance Spark-13749.

    pivot_df = df.groupBy("Product", "Country") \
        .sum("Amount") \
        .groupBy("Product") \
        .pivot("Country") \
        .sum("sum(Amount)")
    pivot_df.show()
    

    The above two examples return the same output but with better performance.

    3. Unpivot DataFrame

    Unpivot is a reverse operation, achieved by rotating column values into row values. PySpark doesn’t have an unpivot function, hence the stack() function is used. The code below converts column countries to rows.

    unpivot_df = pivot_df.select("Product", 
        expr("stack(3, 'Canada', Canada, 'China', China, 'Mexico', Mexico) as (Country, Total)")
    ).where("Total is not null")
    unpivot_df.show()
    

    It converts the pivoted column “country” to rows.

    +-------+-------+-----+
    |Product|Country|Total|
    +-------+-------+-----+
    | Orange|  China| 4000|
    |  Beans|  China| 1500|
    |  Beans| Mexico| 2000|
    | Banana| Canada| 2000|
    | Banana|  China|  400|
    |Carrots| Canada| 2000|
    |Carrots|  China| 1200|
    +-------+-------+-----+
    

    4. Transpose or Pivot without Aggregation

    Can we transpose or pivot a PySpark DataFrame without aggregation?

    Indeed, it's possible, but unfortunately, you can’t achieve this using the Pivot function directly. However, pivoting or transposing the DataFrame structure without aggregation from rows to columns and columns to rows can be done using workaround methods in PySpark. Please refer to this discussion for examples.

    The complete code can be downloaded from this GitHub repository.

    Introduction to PySpark for Data Engineering — DataFrame Wider Transformation

    Introduction to PySpark

    Setup PySpark Environment

    SparkSession & SparkContext

    Resilient Distributed Datasets (RDDs)

    Apache Spark Concepts

    Cache, Persistence and Shared Variables

    DataFrame Introduction

    DataFrame Narrow Transformation

    DataFrame Wider Transformation

    DataFrame Actions

    PySpark SQL Functions

    Advanced DataFrame Features

    PySpark SQL

    Spark Read & Write CSV Files

    Working with JSON Files

    Working with Parquet Files

    What Next?

    Tutorial Not Found