PySpark - Drop Column from DataFrame

Column removal is one of the most frequent operations in PySpark data pipelines. Whether you're cleaning raw data, reducing memory footprint before expensive operations, removing personally...

Key Insights

  • PySpark DataFrames are immutable—drop() returns a new DataFrame rather than modifying the original, so you must reassign or chain operations
  • Use drop() when removing specific columns, but prefer select() when you know exactly which columns to keep (often more maintainable)
  • Dropping columns conditionally based on data types, patterns, or null percentages requires combining DataFrame metadata inspection with list comprehensions

Introduction

Column removal is one of the most frequent operations in PySpark data pipelines. Whether you’re cleaning raw data, reducing memory footprint before expensive operations, removing personally identifiable information (PII), or preparing datasets for machine learning models, knowing how to efficiently drop columns is essential.

PySpark provides several approaches for column removal, each suited to different scenarios. The primary method is drop(), but understanding when to use alternatives like select() and how to conditionally remove columns based on metadata will make your data transformations more robust and maintainable.

Let’s start with a sample DataFrame that we’ll use throughout this article:

from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StructField, StringType, IntegerType, DoubleType

spark = SparkSession.builder.appName("DropColumnExample").getOrCreate()

data = [
    (1, "Alice", "alice@email.com", 28, 75000.0, None),
    (2, "Bob", "bob@email.com", 35, 85000.0, "Engineering"),
    (3, "Charlie", None, 42, 95000.0, "Sales"),
    (4, "Diana", "diana@email.com", None, 70000.0, "Marketing")
]

schema = StructType([
    StructField("id", IntegerType(), True),
    StructField("name", StringType(), True),
    StructField("email", StringType(), True),
    StructField("age", IntegerType(), True),
    StructField("salary", DoubleType(), True),
    StructField("department", StringType(), True)
])

df = spark.createDataFrame(data, schema)
df.show()

This gives us a DataFrame with six columns of mixed types and some null values to work with.

Basic Column Dropping with drop()

The drop() method is the most straightforward way to remove columns from a PySpark DataFrame. It accepts column names as arguments and returns a new DataFrame without those columns.

Here’s how to drop a single column:

# Drop the email column
df_no_email = df.drop("email")
df_no_email.show()

# Verify the column is gone
print("Original columns:", df.columns)
print("After drop:", df_no_email.columns)

Output:

Original columns: ['id', 'name', 'email', 'age', 'salary', 'department']
After drop: ['id', 'name', 'age', 'salary', 'department']

You can also verify column removal by examining the schema:

df_no_email.printSchema()

Remember that PySpark DataFrames are immutable. The original df remains unchanged—drop() returns a new DataFrame. If you want to work with the modified version, either reassign it or chain operations:

# Reassignment
df = df.drop("email")

# Or chain operations
result = df.drop("email").filter(df.age > 30)

Dropping Multiple Columns

When you need to remove multiple columns, drop() accepts multiple column names as separate arguments:

# Drop multiple columns by passing them as separate arguments
df_minimal = df.drop("email", "department", "age")
df_minimal.show()

For a more dynamic approach, especially when working with a programmatically generated list of columns, use the unpacking operator:

# Define columns to drop in a list
columns_to_drop = ["email", "department", "age"]

# Use the unpacking operator (*) to pass list elements as arguments
df_minimal = df.drop(*columns_to_drop)
df_minimal.show()

This pattern is particularly useful when you’re building ETL pipelines where the columns to drop might be configured externally or determined at runtime:

# Example: Drop columns based on configuration
sensitive_columns = ["email"]
optional_columns = ["department"]
columns_to_remove = sensitive_columns + optional_columns

df_cleaned = df.drop(*columns_to_remove)

Conditional Column Dropping

Real-world scenarios often require dropping columns based on conditions rather than explicit names. PySpark’s schema metadata enables powerful conditional column removal patterns.

Drop Columns by Data Type

To remove all columns of a specific data type, iterate through the schema:

from pyspark.sql.types import StringType

# Drop all string columns
string_columns = [field.name for field in df.schema.fields if isinstance(field.dataType, StringType)]
print("String columns to drop:", string_columns)

df_no_strings = df.drop(*string_columns)
df_no_strings.show()

This is useful when you want to keep only numeric columns for statistical analysis or machine learning features.

Drop Columns by Name Pattern

Use regular expressions to drop columns matching a pattern:

import re

# Drop columns containing 'email' or starting with 'dep'
pattern = re.compile(r'email|^dep')
columns_to_drop = [col for col in df.columns if pattern.search(col)]
print("Columns matching pattern:", columns_to_drop)

df_filtered = df.drop(*columns_to_drop)
df_filtered.show()

Drop Columns with High Null Percentage

Remove columns that are mostly empty:

from pyspark.sql.functions import col, count, when

def drop_high_null_columns(df, threshold=0.5):
    """Drop columns where null percentage exceeds threshold"""
    total_rows = df.count()
    columns_to_drop = []
    
    for column in df.columns:
        null_count = df.filter(col(column).isNull()).count()
        null_percentage = null_count / total_rows
        
        if null_percentage > threshold:
            columns_to_drop.append(column)
            print(f"Dropping {column}: {null_percentage:.2%} nulls")
    
    return df.drop(*columns_to_drop)

# Drop columns with more than 30% null values
df_clean = drop_high_null_columns(df, threshold=0.3)
df_clean.show()

This approach is valuable during exploratory data analysis when you want to eliminate columns with insufficient data.

Alternative Methods: select() vs drop()

While drop() specifies what to remove, select() specifies what to keep. Sometimes select() is more appropriate:

# Using select() to keep specific columns
df_selected = df.select("id", "name", "salary")
df_selected.show()

# Equivalent to dropping email, age, and department
df_dropped = df.drop("email", "age", "department")

When to use select() over drop():

  • When you know exactly which columns you need (more explicit and maintainable)
  • When keeping fewer columns than dropping
  • When you want to reorder columns simultaneously

When to use drop():

  • When removing a small number of columns from a large schema
  • When column removal is based on conditions
  • When you want to preserve column order

Here’s a practical example showing the maintainability advantage of select():

# More maintainable: explicit about what's needed
required_columns = ["id", "name", "salary"]
df_model_ready = df.select(*required_columns)

# Less maintainable: must update if schema changes
df_model_ready = df.drop("email", "age", "department")

Performance-wise, both methods are comparable for most use cases. PySpark’s Catalyst optimizer handles them efficiently. However, select() can be slightly more efficient when keeping very few columns from a wide DataFrame because it explicitly tells Spark which columns to read.

Common Pitfalls and Best Practices

Handling Non-Existent Columns

Attempting to drop a column that doesn’t exist raises an AnalysisException:

# This will raise an error
# df.drop("nonexistent_column")

# Safe approach: check column existence first
def safe_drop(df, columns):
    """Drop columns only if they exist"""
    if isinstance(columns, str):
        columns = [columns]
    
    existing_columns = [col for col in columns if col in df.columns]
    missing_columns = [col for col in columns if col not in df.columns]
    
    if missing_columns:
        print(f"Warning: Columns not found: {missing_columns}")
    
    return df.drop(*existing_columns) if existing_columns else df

# Usage
df_safe = safe_drop(df, ["email", "nonexistent_column", "age"])
df_safe.show()

Efficient Column Dropping in Chains

When chaining multiple operations, combine column drops when possible:

# Less efficient: multiple drop operations
df_result = df.drop("email").drop("age").drop("department")

# More efficient: single drop operation
df_result = df.drop("email", "age", "department")

# Even better: combine with other transformations
df_result = (df
    .drop("email", "age", "department")
    .filter(col("salary") > 70000)
    .orderBy("salary", ascending=False))

Working with Duplicate Column Names

If your DataFrame has duplicate column names (which can happen after joins), use column objects instead of strings:

from pyspark.sql.functions import col

# Drop specific column by reference
df_no_dup = df.drop(df.email)  # or df.drop(df["email"])

Memory Considerations

Dropping columns doesn’t immediately free memory in Spark’s execution model. The original DataFrame’s data remains in memory until garbage collected. For large datasets, explicitly cache the result if you’ll reuse it:

df_optimized = df.drop("email", "department").cache()
df_optimized.count()  # Trigger caching

Conclusion

PySpark provides flexible approaches for dropping columns from DataFrames. Use drop() for explicit column removal, especially when removing a small number of columns or working with conditional logic. Consider select() when you know exactly which columns you need—it’s often more maintainable.

For production pipelines, implement safe dropping with existence checks, combine multiple drop operations to reduce overhead, and leverage conditional dropping patterns for dynamic schema handling. Understanding DataFrame immutability is crucial: always reassign or chain operations since drop() returns a new DataFrame.

The choice between methods depends on your specific use case: drop() for targeted removal, select() for explicit retention, and conditional patterns for dynamic schema management. Master all three approaches to write cleaner, more maintainable PySpark code.

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.