100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

DataFrames Basics

How Spark's DataFrame API represents distributed, schema-aware tabular data and why it outperforms hand-written RDD code.

RDDs & DataFramesBeginner8 min readJul 10, 2026
Analogies

What Is a Spark DataFrame?

A Spark DataFrame is a distributed collection of rows organized into named columns with a defined schema, conceptually similar to a table in a relational database or a pandas DataFrame, but able to scale across a cluster. Internally, a DataFrame is a Dataset[Row] built on top of RDDs, but because Spark knows the column names and types up front, it can apply the Catalyst optimizer and Tungsten's binary in-memory format, which plain RDDs of arbitrary objects cannot benefit from.

🏏

Cricket analogy: It's like a scorecard versus a raw pile of loose notes; a scorecard has named columns for runs, balls, and fours for every batsman, letting the scorer instantly compute totals, whereas loose notes about 'that six over midwicket' require manual parsing every time.

Creating DataFrames

DataFrames are most commonly created by reading structured or semi-structured data with the spark.read API, which supports formats like CSV, JSON, Parquet, and Avro out of the box, or by calling spark.createDataFrame() on an existing RDD or a Python list of Row objects paired with a schema. Once loaded, show(), printSchema(), and describe() give a quick first look at the data's shape, types, and basic statistics.

🏏

Cricket analogy: It's like a team analyst importing an entire season's match data from the official scoring app's export (spark.read) versus manually typing a handful of scores into a new spreadsheet for a quick practice analysis (createDataFrame).

python
from pyspark.sql import SparkSession

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

# Read a CSV file into a DataFrame with an inferred schema
df = spark.read.csv("s3://data/sales_2026.csv", header=True, inferSchema=True)

df.printSchema()
# root
#  |-- order_id: integer (nullable = true)
#  |-- region: string (nullable = true)
#  |-- amount: double (nullable = true)

df.show(5)
df.describe(["amount"]).show()

# Build a small DataFrame directly from Python objects for testing
sample_df = spark.createDataFrame(
    [(1, "west", 250.0), (2, "east", 400.0)],
    schema=["order_id", "region", "amount"]
)

Core DataFrame Operations

The DataFrame API is declarative: you describe what result you want using methods like select(), filter(), withColumn(), and groupBy().agg(), and Spark's Catalyst optimizer decides how to execute it efficiently. Column expressions can be chained, for example df.filter(col('amount') > 100).groupBy('region').agg(sum('amount')), and each step returns a new DataFrame since DataFrames are immutable just like RDDs.

🏏

Cricket analogy: It's like a captain declaring the desired outcome, 'bowl a maiden over to this batsman', and letting the bowler choose the exact line and length, rather than micromanaging every millimeter of the arm action, which is what a declarative select/filter/groupBy chain does versus manual looping.

DataFrame transformations like filter() and select() are, like RDD transformations, lazy. Nothing executes until an action such as show(), collect(), or write() is called, which means Catalyst gets to see and optimize the entire chain of select/filter/groupBy calls as a single logical plan.

DataFrames vs. Plain RDDs

Because a DataFrame carries an explicit schema, Spark can generate specialized, JIT-compiled bytecode for operations like filtering a column or computing a sum, and store data in Tungsten's compact binary row format instead of generic Java objects, both of which typically make DataFrame operations significantly faster than the equivalent hand-written RDD code. RDDs remain useful when you need full control over partition-level logic or are working with unstructured data that doesn't fit a schema.

🏏

Cricket analogy: It's like the difference between a bowling machine calibrated to a known pitch length and bounce (schema-aware, precise) versus a bowler guessing blind on an unfamiliar surface every ball (generic RDD, no shortcuts) -- the calibrated machine is consistently faster and more accurate.

Dropping down to df.rdd to run custom Python logic with map() defeats the purpose of using DataFrames: it forces Spark to deserialize Tungsten's optimized binary format back into generic Python/Java objects, losing Catalyst optimization for that step. Prefer built-in column functions or a pandas UDF before reaching for raw RDD operations on a DataFrame.

  • A DataFrame is a distributed table with a named, typed schema, implemented internally as a Dataset[Row] on top of RDDs.
  • DataFrames are most often created via spark.read (CSV, JSON, Parquet, Avro) or spark.createDataFrame() from existing data.
  • printSchema(), show(), and describe() give a quick first look at structure and basic statistics.
  • The API is declarative: select(), filter(), withColumn(), and groupBy().agg() describe intent, and Catalyst decides execution strategy.
  • DataFrames outperform equivalent RDD code because Catalyst and Tungsten exploit the known schema for optimized execution and compact memory layout.
  • Dropping to df.rdd for custom logic loses Catalyst optimization and should be avoided when a built-in column function would work instead.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#ApacheSparkStudyNotes#DataFramesBasics#DataFrames#Spark#DataFrame#Creating#StudyNotes#SkillVeris#ExamPrep