Built with Tutify.io

    AIStudyLabs

    Explain PySpark randomSplit() Function

    Explain PySpark randomSplit() Function

    In PySpark, the randomSplit() function is used to divide a DataFrame into multiple smaller DataFrames based on specified weights. Unlike simple row selection, randomSplit() splits the dataset into training, validation, and test sets or any other proportion you need.

    For example, if your dataset contains 1 million rows, you might want to split it into 70% training data, 20% validation data, and 10% test data.

    In simple terms, randomSplit() randomly distributes rows across multiple DataFrames according to the fractions you provide.

    In this article, we will learn how the randomSplit() function works in PySpark and how you can use it to split DataFrames efficiently into training, validation, and test datasets.

    Key Points-

    <a id="h-pyspark-randomsplit-function"></a>

    PySpark randomSplit() Function

    The randomSplit() function splits a DataFrame into multiple smaller DataFrames according to the weights you provide.

    <a id="h-syntax"></a>

    Syntax

    Below is the syntax of the randomSplit() function.

    
    # Syntax of randomSplit() function
    DataFrame.randomSplit(weights, seed=None)
    

    <a id="h-parameters"></a>

    Parameters

    Return Value

    Returns a list of DataFrames split according to the specified weights.

    Usage of PySpark randomSplit()

    You can use randomSplit() to split a DataFrame into multiple subsets. By providing a list of weights corresponding to training, validation, and test sets, Spark randomly returns rows to each split according to the specified ratios.

    For example, to split a dataset into 70% training, 20% validation, and 10% test set.

    
    # Use randomsplit() to divide DattaFrame into multiple parts
    from pyspark.sql import SparkSession
    
    # Create Spark session
    spark = SparkSession.builder \
        .master("local[1]") \
        .appName("AIStudyLabs.com") \
        .getOrCreate()
    
    # Create sample DataFrame
    data = spark.range(0, 100)
    data.show()
    
    # Split the DataFrame: 70% train, 20% validation, 10% test
    train_df, val_df, test_df = data.randomSplit([0.7, 0.2, 0.1], seed=42)
    
    # Show the counts of each split
    print("Train count:", train_df.count())
    print("Validation count:", val_df.count())
    print("Test count:", test_df.count())
    

    Yields below the output.

    The above code creates a DataFrame with 100 rows and splits it into three DataFrames according to the given ratios. Note that counts may not match exactly because the split is random; fractions are approximate.

    <a id="h-using-randomsplit-for-training-and-test-sets"></a>

    Using randomSplit() for Training and Test Sets

    The most common use case of randomSplit() is dividing a dataset into training and test sets for machine learning. To achieve this, you pass two weights into the function along with a seed value, which gives you the training and test DataFrames.

    
    # Split DataFrame into training (80%) and test (20%)
    train_df, test_df = data.randomSplit([0.8, 0.2], seed=1)
    
    # Show first 5 rows of training set
    train_df.show(5)
    

    Yields below the output.

    Here, the dataset is divided into 80% training and 20% testing. The seed ensures reproducibility, so you get the same split every time you run the code.

    Using randomSplit() with Multiple DataFrames

    You can also divide a DataFrame into more than two or three parts if needed. By providing a list of weights to the function, Spark will randomly create multiple split DataFrames based on those proportions.

    
    # Split into four DataFrames
    df1, df2, df3, df4 = data.randomSplit([0.4, 0.3, 0.2, 0.1], seed=10)
    
    print("DF1 count:", df1.count())
    print("DF2 count:", df2.count())
    print("DF3 count:", df3.count())
    print("DF4 count:", df4.count())
    
    # Output:
    # DF1 count: 33
    # DF2 count: 32
    # DF3 count: 24
    # DF4 count: 11
    

    In this example, the dataset is divided into 40%, 30%, 20%, and 10%. PySpark normalizes weights automatically, so they don’t need to sum to 1.

    <a id="h-handling-imbalanced-datasets"></a>

    Handling Imbalanced Datasets

    When working with imbalanced datasets, randomSplit() can produce unexpected results because it doesn’t preserve class distribution.

    
    from pyspark.sql import functions as F
    
    # Create imbalanced dataset
    data = [(i, 0) for i in range(991)] + [(i, 1) for i in range(991, 1000)]
    df = spark.createDataFrame(data, ["id", "is_clicked"])
    
    # Split dataset
    train_df, test_df = df.randomSplit([0.7, 0.3], seed=42)
    
    print("Original counts:", df.groupBy("is_clicked").count().collect())
    print("Train counts:", train_df.groupBy("is_clicked").count().collect())
    print("Test counts:", test_df.groupBy("is_clicked").count().collect())
    
    # Output:
    # Original counts: [Row(is_clicked=0, count=991), Row(is_clicked=1, count=9)]
    # Train counts: [Row(is_clicked=0, count=738), Row(is_clicked=1, count=6)]
    # Test counts: [Row(is_clicked=0, count=253), Row(is_clicked=1, count=3)]
    

    You may notice that after splitting, the is_clicked column (imbalanced target variable) doesn’t appear evenly distributed across the train and test sets. This happens because randomSplit() doesn’t preserve class distribution; it only randomly distributes rows.

    <a id="h-fix-distribution-issues"></a>

    Fix Distribution Issues

    To preserve distribution across splits, you can try the following approaches:

    <a id="h-add-a-random-column-and-sort-before-splitting"></a>

    Add a Random Column and Sort Before Splitting

    You can use the rand() function to generate a random column, sort the DataFrame by it, and then apply randomSplit() to achieve a more uniform distribution.

    
    # Sample DataFrame
    data = [(i, i % 2) for i in range(1, 11)]  # (id, is_clicked) with 0/1
    df = spark.createDataFrame(data, ["id", "is_clicked"])
    
    # Add random column and split
    df = df.withColumn("rand", F.rand(seed=42)).orderBy("rand")
    train_df, test_df = df.randomSplit([0.7, 0.3], seed=42)
    
    print("Training Data:")
    train_df.show()
    
    print("Testing Data:")
    test_df.show()
    
    # Output
    # Training Data:
    # +---+----------+-------------------+
    # | id|is_clicked|               rand|
    # +---+----------+-------------------+
    # |  1|         1|  0.619189370225301|
    # |  2|         0| 0.5096018842446481|
    # |  4|         0|0.26322809041172357|
    # |  5|         1| 0.6702867696264135|
    # |  6|         0| 0.5173283545794627|
    # |  8|         0|0.06993233728279169|
    # +---+----------+-------------------+
    
    # Testing Data:
    # +---+----------+------------------+
    # | id|is_clicked|              rand|
    # +---+----------+------------------+
    # |  3|         1|0.8325259388871524|
    # |  7|         1|0.9991441647585968|
    # |  9|         1|0.9696695610826327|
    # | 10|         0|0.7959575617927873|
    # +---+----------+------------------+
    

    <a id="h-use-filter-instead-of-randomsplit"></a>

    Use Filter Instead of randomSplit

    You can also split your dataset into train and test sets by creating a random column with rand() and applying filter conditions. This approach ensures that the distribution remains uniform without relying on randomSplit().

    
    # Sample DataFrame
    data = [(i, i % 2) for i in range(1, 11)]  # (id, is_clicked) with 0/1
    df = spark.createDataFrame(data, ["id", "is_clicked"])
    
    # Add random column
    df = df.withColumn("rand", F.rand(seed=42))
    
    # Split using filter
    train_df = df.filter(df.rand < 0.7)
    test_df = df.filter(df.rand >= 0.7)
    
    print("Training Data:")
    train_df.show()
    
    print("Testing Data:")
    test_df.show()
    
    # Output:
    # Training Data:
    # +---+----------+-------------------+
    # | id|is_clicked|               rand|
    # +---+----------+-------------------+
    # |  1|         1|  0.619189370225301|
    # |  2|         0| 0.5096018842446481|
    # |  4|         0|0.26322809041172357|
    # |  5|         1| 0.6702867696264135|
    # |  6|         0| 0.5173283545794627|
    # |  8|         0|0.06993233728279169|
    # +---+----------+-------------------+
    
    # Testing Data:
    # +---+----------+------------------+
    # | id|is_clicked|              rand|
    # +---+----------+------------------+
    # |  3|         1|0.8325259388871524|
    # |  7|         1|0.9991441647585968|
    # |  9|         1|0.9696695610826327|
    # | 10|         0|0.7959575617927873|
    

    This gives you a cleaner and reproducible split with uniform distribution.

    <a id="h-use-sampleby-for-stratified-splits"></a>

    Use sampleBy() for Stratified Splits

    You can use the sampleBy() function to preserve the class distribution when splitting imbalanced datasets. Here, we keep 70% of each class (0 and 1) in the training set, and the rest goes into the test set.

    
    # Sample DataFrame
    data = [(i, i % 2) for i in range(1, 11)]  # (id, is_clicked) with 0/1
    df = spark.createDataFrame(data, ["id", "is_clicked"])
    
    # Stratified sampling: Keep 70% of each class in training set
    fractions = {0: 0.7, 1: 0.7}  
    train_df = df.sampleBy("is_clicked", fractions, seed=42)
    test_df = df.subtract(train_df)
    
    print("Training Data:")
    train_df.show()
    
    print("Testing Data:")
    test_df.show()
    
    # Output:
    # Training Data:
    # +---+----------+
    # | id|is_clicked|
    # +---+----------+
    # |  1|         1|
    # |  2|         0|
    # |  4|         0|
    # |  5|         1|
    # |  6|         0|
    # |  8|         0|
    # +---+----------+
    
    # Testing Data:
    # +---+----------+
    # | id|is_clicked|
    # +---+----------+
    # |  7|         1|
    # |  9|         1|
    # |  3|         1|
    # | 10|         0|
    # +---+----------+
    

    This ensures both splits maintain the same class distribution.

    Key Differences Between sample() and randomSplit()

    The table below provides a complete comparison of the features of sample() and randomSplit().

    | Feature | sample() | randomSplit() | | --- | --- | --- | | Type of Operation | Random sampling | Random splitting | | Output | Single DataFrame | Multiple DataFrames (list) | | Fraction | Single fraction | List of weights | | Replacement | Can be with/without replacement | Always without replacement | | Use Case | Quick random sampling | Train/test/validation splits |

    <a id="h-frequently-asked-questions-of-pyspark-randomsplit"></a>

    Frequently Asked Questions of PySpark randomSplit()

    It divides a DataFrame into multiple smaller DataFrames based on the weights you provide. The split is random and approximate, not exact.

    Nothing special — Spark automatically normalizes them. For example, [7, 2, 1] is treated the same as [0.7, 0.2, 0.1].

    randomSplit() → splits the DataFrame into parts randomly, without considering group distribution.
    sampleBy() → performs stratified sampling, ensuring each group is sampled proportionally to the given fractions.

    randomSplit() does not preserve class distribution. For imbalanced datasets, use sampleBy() to perform stratified sampling and maintain balance across splits.

    The underlying partitions in a DataFrame do not guarantee order. This can sometimes lead to overlapping or clustered splits. To fix it, add a random column with rand() and sort the DataFrame before splitting, or use filter() instead of randomSplit().

    <a id="h-conclusion"></a>

    Conclusion

    In this article, we learned how to use PySpark’s randomSplit() function to split DataFrames randomly into training, validation, and test sets.

    We also explored:

    Use randomSplit() for quick, probabilistic splits, and sampleBy() when class distribution needs to be preserved.

    Happy Learning!!

    <a id="h-reference"></a>

    Reference

    <a id="h-related-articles"></a>

    Related Articles