Contents/ Part XXIV Β· Advanced & Applied Topics/ Chapter 149

Big Data & Scaling

Big data is not a size. It is the moment your usual approach stops working: the file will not open, the job does not finish, the machine runs out of memory. This chapter walks the ladder of fixes in order, from the one-line change that buys you three times the headroom to the cluster you probably do not need yet.

⏱️ ~26 min read
🐍 Notebook included
πŸ“Š Chapter 149

There is no row count at which data becomes big. The honest definition is relative: data is big when it no longer fits the way you are used to working. On a laptop that threshold might be ten million rows; for a bank it might be ten billion events a day. What matters is that the symptoms are always the same, and so are the remedies, and they come in a strict order of cost. Most teams skip straight to the expensive one.

πŸ—„οΈ
Big data describes datasets whose volume, velocity, or variety exceed what a single machine and a single pass can comfortably handle. Scaling up means a bigger machine; scaling out means many machines, which buys capacity at the price of coordination.
πŸͺœ
Climb the ladder in order

Before you reach for a cluster, ask three questions. Am I storing this wastefully? Better types and a columnar file often cut the cost by more than half. Do I need it all at once? Streaming the data in chunks turns a memory problem into a patience problem. Can the work be split? If so, more cores may be enough. A cluster is the answer to the question that survives all three, and it brings a new set of problems with it.

1

When Data Outgrows One Machine

The classic description of big data is the five Vs. They are worth knowing because each one breaks a different part of your workflow, and the fix depends on which one is actually biting you.

The VWhat it meansWhat it breaks, and the usual remedy
VolumeSheer quantity: terabytes, billions of rows. Memory and storage. Remedy: better types, columnar formats, chunking, partitioning, then distributed storage.
VelocityData arriving continuously and fast. Batch thinking. A nightly job cannot answer a question about the last five minutes. Remedy: stream processing.
VarietyText, images, logs, JSON, audio, not just neat tables. The schema. Remedy: flexible storage (a data lake) plus a schema applied when you read, not when you write.
VeracityHow much of it you can trust. Your conclusions. Scale multiplies noise, duplicates, and silent pipeline failures rather than averaging them away.
ValueWhether any of it is worth the cost. The budget. The V that gets skipped, and the one that decides whether the project should exist.

Notice that only the first is about size. A few gigabytes of messy, fast-moving, untrustworthy data is a harder engineering problem than a clean hundred-gigabyte table. Once you know which V you have, the ladder below tells you how far you actually need to climb.

The scaling ladder: climb only as far as you have to 1 · Fits in memory pandas, one machine just do the work 2 · Bigger than memory smaller dtypes and categories columnar storage (Parquet) read it in chunks use more cores still one machine 3 · Genuinely distributed many machines: Spark distributed storage fault tolerance built in new costs: network shuffles skew and stragglers cluster to operate increasing cost, complexity, and number of things that can go wrong Most “big data” problems end at step 2. A modern laptop has more memory than the clusters that made Hadoop famous.
Each step up buys capacity and costs complexity. Step 2 is where the best returns are, and it is the step most often skipped: teams jump from a struggling laptop straight to a cluster, and inherit shuffles, skew, and an operations burden they did not need.
2

Store It Smarter: Types, Columns, and Partitions

The cheapest capacity you will ever buy comes from storing the same data more sensibly. Three ideas do most of the work, and none of them changes a single result.

Right-size the types. By default a column of whole numbers becomes a 64-bit integer, whether it holds nine-digit identifiers or the hour of the day. A text column becomes Python objects, one per row, even when it repeats the same six city names for millions of rows. Store the hour as an 8-bit integer and the city as a category, which keeps integer codes plus one small lookup table, and the footprint collapses. In the notebook this one step takes the ride logs from 2.70 MB to 0.80 MB, a 70 percent saving, with identical numbers coming out the other end.

Store columns, not rows. A CSV is text laid out row by row, so reading one column means reading every byte of every row and parsing it. Parquet stores each column together, compressed, with summary statistics in the footer. Two things follow. The file shrinks, because a column of repeated city names compresses far better than the same values scattered through rows. And you can read two columns out of eleven without touching the rest, which is called column pruning. On the 500,000-row file in the notebook, Parquet is 4.7 times smaller (6.4 MB against 30.2 MB), and reading just two columns is about 32 times faster than reading the CSV.

Partition on what you filter by. Split the data into folders by a column you query constantly, such as date, and a query for one day can skip every other folder before reading a byte. Engines call this predicate pushdown: the filter is pushed down to the storage layer instead of being applied after loading everything. The catch is that partitioning on a column with very many distinct values, such as a customer id, produces millions of tiny files and makes everything slower. Partition on something coarse.

⚠️
Do not average the averages

The moment you process data in pieces, one arithmetic rule starts to matter. Sums, counts, minimums, and maximums can be computed per chunk and combined at the end. Means cannot: the average of ten chunk averages is only correct when every chunk is the same size. Carry a sum and a count from each chunk and divide once at the end. The same caution applies to medians and percentiles, which cannot be combined from pieces at all without either a full pass or an approximation algorithm.

3

Divide and Conquer: MapReduce, Spark, and the Modern Stack

When one machine really is not enough, the work has to be split across many. Almost every system for doing that rests on a single pattern, introduced by Google and made famous by Hadoop: map, shuffle, reduce.

Map, shuffle, reduce: the pattern under every distributed engine INPUT SPLITS MAP SHUFFLE REDUCE rides 1-8kblock A rides 8-16kblock B rides 16-25kblock C mapper 1(city, fare) mapper 2(city, fare) mapper 3(city, fare) every pair with the same key is routed to one reducer this is the step that crosses the network, so this is the step that costs reduce “Metro City”186,700 total reduce “Riverton”92,353 total reduce “Lakeside”63,416 total
Mapping is embarrassingly parallel: each block is handled independently, anywhere. Reducing is cheap once the data has arrived. The shuffle in the middle is the only stage that moves data between machines, which is why almost every performance problem in a distributed job traces back to it.

The notebook writes this out in about fifteen lines of plain Python and gets exactly what a one-line groupby gets: 25,000 records mapped into 6 shuffled keys. That equivalence is the point. A distributed groupby is not a different idea, it is the same idea with a network in the middle.

Hadoop made this practical at scale with a distributed file system and a job scheduler, but it wrote every intermediate result to disk, which made multi-step work slow. Spark replaced it by keeping data in memory between steps and by being lazy: your transformations (filter, select, join) build up a plan rather than running, and nothing happens until an action (count, collect, write) demands an answer. Because it sees the whole plan first, it can optimize it, for instance by pushing your filter down to the read so that less data ever leaves disk.

The stack kept moving. Storage split from compute, so a data lakehouse now holds Parquet files with a transaction layer (Delta Lake, Apache Iceberg) over the top. Single-node engines got dramatically faster, so DuckDB and Polars handle on one machine what once needed a cluster. And for the velocity problem, Kafka and Flink process events as they arrive instead of waiting for a nightly batch. The vocabulary changes every few years; map, shuffle, reduce does not.

🐒
The straggler problem

A parallel job finishes when its slowest worker finishes, not when the average one does. So the thing that ruins distributed jobs is rarely total volume, it is imbalance. If one key holds half the rows, one worker does half the work while the rest sit idle, and adding machines does not help at all. This is data skew, and it is the single most common reason a cluster fails to deliver the speedup it promised.

4

Real-World Example: Scaling a Ride-Log Analysis

Ride-hailing logs are a fair stand-in for the shape of real operational data: one row per event, a few numeric columns, a few repeated text columns, and a geography that is nowhere near evenly distributed. The last property is what makes it useful here.

Real dataset

Ride logs, 25,000 trips across six cities. Each row is one completed ride. ride_id identifies the trip and rider_id the passenger, so repeat riders appear many times. city is where the ride started and vehicle_type is the tier booked (standard, xl, premium, eco). pickup_hour is the hour of day from 0 to 23, distance_km the trip distance and duration_min its length in minutes. surge_multiplier is the demand multiplier applied to the price, fare the dollars charged, payment_type how it was paid (card, wallet, cash), and rating the passenger's score from 1.0 to 5.0.

The file opens in Excel without complaint, and that is deliberate. Nothing here needs a cluster; the point is that the techniques are what scale, and you can learn all of them at a size you can still check by eye. The notebook inflates the logs to 500,000 rows (30.2 MB on disk, about 54 MB once loaded) to make the streaming and storage results honest.

One analytical finding is worth pausing on, because it is the kind of thing that only appears once the aggregation runs. Metro City supplies 46 percent of rides but the lowest average fare, about 16.19 dollars against roughly 19.60 everywhere else. It is not underpriced; its trips are simply shorter, because a dense city center produces many short hops while the outlying towns produce fewer, longer journeys. A revenue-per-ride league table would rank Metro City last and be badly misleading. This is the confounding pattern in operational clothing, and no amount of scale fixes it. Scale gets you the number faster; it does not tell you what the number means.

A job finishes when its slowest worker finishes Partitioned by city: skewed job ends here 46.1% w1w2w3 w4w5w6 one worker carries 2.8x the average load five workers sit idle waiting Hot key salted into 4 pieces: balanced 11.7% more, smaller partitions the tall bar is gone, so the job ends far earlier cost: one extra combining stage
Salting appends a small random number to the hot key so it splits across several partitions, then combines the pieces in a second stage. Total work is unchanged and so is the answer; what changes is how evenly the work is spread, and therefore when the job ends. Use it only when one key genuinely dominates, since the extra stage is not free.
5

Scaling in Machine Learning & AI

Modern AI is the most demanding consumer of these ideas. Training a large model is a distributed systems problem at least as much as a statistical one, and the same vocabulary of partitions, shuffles, and stragglers reappears with different names.

IdeaWhat it does, and where you meet it
Data parallelism Every worker holds a full copy of the model and a different slice of the batch, then gradients are averaged across workers each step. The default way to use many GPUs, and the direct descendant of map and reduce.
Model parallelism The model itself is too large for one device, so its layers or tensors are split across several. Necessary once parameter counts run to billions.
AllReduce The collective operation that averages gradients across all workers without a central bottleneck. This is the shuffle of distributed training, and the step that network speed limits.
Mini-batch training Stochastic gradient descent is itself an out-of-core algorithm: it never needs the whole dataset in memory, only the current batch. Chunking is not a workaround here, it is the method.
Feature stores A shared, versioned layer serving the same feature definitions to training and to production, so the statistics a model learned from match the ones it later sees.
Data pipelines At scale the GPU is often idle waiting for data. Prefetching, sharding files, and columnar formats keep it fed, which is why storage layout is a training-speed decision.
Checkpointing On thousands of machines running for weeks, hardware failure is routine rather than exceptional. Periodic checkpoints turn a crash into a restart instead of a total loss.
Research note

Scale became a research subject in its own right with the neural scaling laws, which found that loss falls as a smooth power law in model size, dataset size, and compute. The Chinchilla result then showed the field had been building models too large for the data they were trained on: for a fixed compute budget, a smaller model trained on more tokens wins. That is a statistical statement about the efficient allocation of a budget, and it redirected an industry. Scaling is not only an engineering concern; deciding what to scale is a modeling question.

🐍

Companion notebook

Six demonstrations, one machine, no cluster: measure and shrink the memory footprint, aggregate a 500,000-row file in chunks without ever loading it, compare CSV against Parquet for size and read speed, write map, shuffle, and reduce by hand and check it against a groupby, parallelize a bootstrap across eight cores and see Amdahl's law bite, then diagnose the data skew and repair it by salting.

πŸ““ View Notebook β–Ά Open in Colab ⬇ GitHub

Requires pandas, numpy, matplotlib, pyarrow (for Parquet), joblib, and openpyxl. All are preinstalled on Colab.

πŸŽ“ Key Takeaways

  • βœ“Big data is a relative term: it starts where your current approach stops working, which depends on the machine, the deadline, and the question.
  • βœ“The five Vs (volume, velocity, variety, veracity, value) each break something different; identify which one is biting before choosing a fix.
  • βœ“Climb the ladder in order: right-size the types, store columnar, stream in chunks, add cores, and only then add machines.
  • βœ“Carry sums and counts, not means, when you process data in pieces; medians and percentiles do not combine from chunks at all.
  • βœ“Map, shuffle, reduce underlies every distributed engine, and the shuffle is the expensive step because it is the one that crosses the network.
  • βœ“Parallel speedup is always sublinear: coordination costs and Amdahl's law mean eight workers never give you eight times the speed.
  • βœ“Skew, not volume, is what usually kills a job: it ends when the slowest worker ends, so one dominant key can idle an entire cluster. Salting spreads it.
6

Practice Challenges

Five exercises on the ride logs. Full solutions are in the companion solutions notebook.

1

Halve the memory footprint

Downcast every numeric column and convert repeated text to categories. Report the saving, then prove the summary statistics did not move.

Hint: pd.to_numeric(..., downcast=) and astype("category").
2

Average distance, in chunks

Compute the mean trip distance by vehicle type without ever holding the whole file. Remember why you cannot average the chunk averages.

Hint: pd.read_csv(..., chunksize=), and carry sums and counts.
3

Price the format

Write the data as both CSV and Parquet. Compare file size, and compare the time to read a single column from each.

Hint: to_parquet, then read_parquet(columns=[...]).
4

MapReduce the busiest hour

Using map, shuffle, and reduce explicitly (no groupby), count rides per pickup hour and name the peak. Check it against value_counts.

Hint: the key is the hour and the value is 1.
5

Diagnose and repair the skew

Quantify how lopsided the city partitions are, then salt the hot key with 2, 4, and 8 pieces and report how the largest partition shrinks. Confirm the totals survive.

Hint: imbalance = largest partition divided by the mean partition.
πŸ““

Solutions notebook

All five challenges worked in code: automatic downcasting with a before-and-after check, a chunked groupby that matches the full-file answer, a CSV against Parquet comparison on size and single-column read time, MapReduce for the busiest hour, and a skew diagnosis with salting at several strengths.

πŸ““ View Solutions β–Ά Open in Colab ⬇ GitHub
7

Quiz: Test Yourself

Eight questions on the five Vs, storage formats, chunked processing, MapReduce, parallel speedup, and skew. Answer them, hit Check Answers, and keep refining until you score 100%. Your progress is saved.

➑️
Up next

Everything so far has ended at a trained, tested model. From Model to Production (MLOps) closes this part by asking what happens after: how a model is packaged, served, watched for drift, and retrained once the world it learned from moves on. Browse the full Contents for what is published and what is on the way.