Overview

5 Cleaning and Transforming DataFrames

This chapter presents a practical, end-to-end workflow for cleaning and transforming large tabular data with Dask DataFrames. Building on pandas-like syntax, it highlights where distributed execution changes behavior and performance, and underscores why rigorous data cleaning is essential before analysis. Working from the NYC Parking Ticket dataset, the chapter moves from basic column/row navigation to indexing, recoding, joining, and finally exporting clean, analysis-ready data.

Core manipulation begins with selecting, dropping, and renaming columns, and selecting rows via index and slices, with notes on Dask-specific nuances (for example, drop requires axis=1 for columns, and some row-wise operations are better done on small, materialized pandas slices). Missing data handling follows a clear sequence: profile null rates, drop columns with heavy missingness, impute sensible defaults (such as filling a categorical with its most frequent value), drop rows with limited missingness in key fields, and fill remaining gaps with explicit placeholders. The chapter then shows how to recode high-cardinality fields using where and mask to collapse categories (e.g., plate types into PAS/COM/Other and rare vehicle colors into Other). Elementwise transformations with apply (using meta for type hints) convert date strings to datetimes and derive a month–year feature, which is subsequently promoted to the index to speed filtering and future joins.

With a suitable index in place, the chapter demonstrates efficient Boolean filtering and index-aware joins, emphasizing that aligning indices across DataFrames makes inner joins fast and predictable (e.g., enriching citations with monthly temperature data). It also covers concatenation along rows via append, discusses persisting intermediate results to avoid repeated computation, and concludes with writing outputs. For text files, it explains partition-aware CSV writing, optional repartitioning to produce a single file, and common formatting options; for Parquet, it shows simple, partitioned writes with compression. By the end, you have a cleaned, recoded, indexed, and optionally enriched dataset saved to disk, ready for exploration and modeling.

The Data Science with Python and Dask workflow
Description: A picture containing screenshot Description automatically generated
The structure of a DataFrame
The output of Listing 5.3
The output of Listing 5.4
The output of Listing 5.5
The output of Listing 5.6
The output of Listing 5.7
The output of Listing 5.8
A join operation combines two datasets by adding the columns of the right table to the columns of the left table.
We can tell that Jack is my cat because his Owner ID is a key that points to my Person ID
Showing all the key relationships between the Person and Pet tables
New York City Average Monthly Temperature
The output of Listing 5.30
The result of an outer join preserves records that don’t have any relationships
The result of concatenating the Person and More People tables

   Summary

In this chapter you learned

  • Selecting columns from a DataFrame uses square bracket ([…]) notation. You can select more than one column by passing a list of column names into the column selector brackets.
  • The head method shows the first 10 rows of a DataFrame by default. You can also specify a number of rows you want to view.
  • Columns can be dropped from a DataFrame by using the drop method. However, since DataFrames are immutable, the column is not dropped from the original DataFrame.
  • Null values can be removed from DataFrames using the dropna method.
  • Use the drop-assign-rename pattern to replace columns in a DataFrame, such as when parsing or recoding values in a column.
  • Transformation functions can be performed elementwise over a DataFrame using the apply method.
  • Boolean operators (>, <, =, etc.) are supported for filtering DataFrames. If your filter condition requires more than one input value, you can use NumPy style Boolean functions such as isin.
  • Two DataFrames can be relationally joined using the merge method. You can even merge a Pandas DataFrame to a Dask DataFrame!
  • DataFrames can be concatenated (unioned) using the append method.

FAQ

How do I select one or multiple columns in a Dask DataFrame, and why do I sometimes get a Series instead of a DataFrame?Use df['col'] to select a single column, which returns a Series (no column axis). Use df[['col1', 'col2']] (note the double brackets) or a list variable of column names to get a DataFrame. All names passed must exist; otherwise Dask raises a KeyError.
What’s the best way to drop columns, and why must I set axis=1?Use df.drop(['colA', 'colB'], axis=1) to remove columns. In Dask, drop across rows (axis=0) isn’t implemented; omitting axis=1 leads to NotImplementedError. Choose between dropping columns vs selecting columns based on convenience: select when keeping few columns; drop when removing few.
How can I select rows by index in Dask, and can I drop specific rows?Use loc with a scalar index (df.loc[56]) or a slice (df.loc[100:200]). Dask can’t drop rows directly; if you need to drop explicit row indices, materialize a small slice to Pandas (e.g., with head or compute), operate there (e.g., drop), and beware of memory limits.
How do I find and quantify missing values across columns?Use df.isnull().sum() for counts per column. To compute percentages, divide by df.index.size and multiply by 100, then call compute() to execute. Wrapping with a ProgressBar gives visibility into the computation.
What strategies does the chapter use to handle missing data?- Drop columns with very high missingness (e.g., ≥50%) using drop. - Impute categorical columns with the mode (e.g., value_counts → most frequent) via fillna({'col': mode}). - Drop rows with missing values in a subset of columns using dropna(subset=[...]). - For multiple string columns, build a dict of defaults (e.g., 'Unknown') and pass to fillna.
When should I use where vs mask for recoding values?Both operate elementwise with a Boolean condition: where keeps values where condition is True and replaces when False; mask replaces when condition is True and keeps when False. Use where when you want to keep a small whitelist and replace everything else; use mask when you want to replace a small blacklist and keep everything else.
How do I create derived columns with apply, and why is meta required?Use Series.apply(func, meta=...) to transform values. For example, parse dates with datetime.strptime and meta=datetime, then add the result back via assign (and rename if needed). Meta tells Dask the output dtype when it can’t infer it (e.g., datetime), which avoids inference failures.
Why set an index, and what options matter for performance?set_index sorts the DataFrame by a key, enabling fast slicing, filtering, and joins. It can be expensive once, but you can persist or write to Parquet to reuse. If the data is already sorted, pass sorted=True. Let Dask infer partitions or tune with npartitions/divisions for performance.
How do joins and unions work in Dask, and what should I watch out for?- Joins (join) add columns; prefer index-aligned joins for speed. Specify how='inner' to keep only matching keys (default is outer, which preserves non-matching rows with nulls). You can join a small Pandas DataFrame to a Dask DataFrame. Avoid non-aligned joins—they’re slow. - Unions (append/concat) add rows; schemas are aligned by column names and non-overlapping columns get nulls.
How do I write results to CSV or Parquet, and why do I get many files?Dask writes one file per partition by default. For CSV, use df.to_csv('path/partition-*.csv'); to write a single file, repartition to 1 first: df.repartition(npartitions=1).to_csv(...). Customize delimiter, NA text, header/index, and compression via keywords. For Parquet, use df.to_parquet('dir', compression='snappy'); Parquet is directory-based and naturally partitioned.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Data Science with Python and Dask ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Data Science with Python and Dask ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • Data Science with Python and Dask ebook for free