Overview

9 Working with Bags and Arrays

This chapter broadens the Dask toolkit beyond DataFrames by introducing Bags for unstructured, mixed-type collections and Arrays for higher-dimensional numerical work. It explains how Bags mirror Python lists at scale—ideal for raw text, nested JSON, and irregular objects—while Arrays parallelize NumPy for linear algebra and statistics. Using a large set of Amazon product reviews as a running example, the chapter shows how to read text lazily with read_text, manage partitioning with blocksize, and resolve character-encoding issues. It then demonstrates a streaming, delimiter-based parsing strategy that avoids loading whole files into memory: locate byte ranges for records, map parsing functions to those ranges, and assemble a Bag of per-review dictionaries. The result is a clean, parallel-ready collection that preserves Dask’s lazy execution model and scales to much larger datasets.

Data manipulation with Bags is presented in a functional style: you transform collections with map, select records with filter, and aggregate with reduce-like operations. Examples include extracting numeric scores, tagging sentiment based on thresholds, and confirming immutability (transformations produce new Bags without altering the original). The chapter builds richer filters, such as computing a “helpfulness” ratio to drop low-signal reviews, and compares means and average review lengths to reveal that longer reviews are more likely to be deemed helpful. It introduces foldby for grouped aggregations across partitions, explaining binop and combine functions and using them to count reviews per star rating—surfacing the dataset’s polarization toward five- and one-star reviews. Throughout, progress bars and compute calls make the lazy plan explicit and measurable.

To bridge unstructured and structured analysis, the chapter converts Bag outputs to Arrays and DataFrames, supplying meta to to_dataframe and applying familiar descriptive statistics. It then integrates NLTK for parallel text mining: extract and lowercase review text, tokenize, remove stopwords, build bigrams, flatten nested structures, and use foldby plus topk to surface the most frequent phrases. Iteratively refining stopwords cleans out HTML artifacts and site-specific tokens, after which separate analyses for negative reviews highlight distinct complaint patterns (for example, phrases around taste or wasted money). The key takeaway is a practical workflow: parse messy text into a Bag, transform and filter it functionally, fold for grouped aggregates, and materialize Arrays/DataFrames for numerical routines—leveraging Dask’s parallelism end-to-end for scalable, flexible analysis.

An example comparison of structured and unstructured data
The Data Science with Python and Dask Workflow
Description: A picture containing screenshot Description automatically generated
There’s a pattern that we can use to split the text into individual reviews
Our custom text parsing algorithm to implement using Dask Delayed
A visual representation of the recursive delimiter search function
Mapping the parsing code to the review data
An example of a fold operation
The descriptive statistics of the Review Scores and Helpfulness
An example of stopwords

   Summary

In this chapter you learned

  • Unstructured data, such as text, doesn’t lend itself well to being analyzed using DataFrames. Dask Bags are a more flexible solution that are useful for manipulating unstructured data.
  • Bags are unordered and do not have any concept of an index (unlike DataFrames). To access elements of a Bag, the take method can be used.
  • The map method is used to transform each element of a Bag using a user-defined function.
  • The foldby function makes it possible to aggregate elements of a Bag before mapping a function over them. This can be used for all sorts of aggregate-type functions.
  • When analyzing text data, tokenizing the text and removing stopwords helps extract the underlying meaning of the text.
  • Bigrams are used to extract phrases from text that may have more meaning than their constituent words (e.g. “not good” versus “not” and “good” in isolation).

FAQ

What are Dask Bags, and when should I use them instead of DataFrames or Arrays?Bags are parallelized, general Python collections (most like lists) that can hold any Python object and do not require a fixed schema or shape. Use Bags when your data is unstructured or semi-structured (raw text, nested JSON, mixed types). Use DataFrames for tabular, 2D data and Arrays for n-dimensional numerical data and linear algebra. Bags excel at reading, transforming, and analyzing text or heterogeneous records, then you can convert to Arrays/DataFrames for numeric/statistical work.
How do I read unstructured text into a Bag, and can I read multiple or compressed files?Use dask.bag.read_text(path, encoding=..., blocksize=...). It lazily creates a Bag where each element is a line. You can pass a glob (e.g., "logs/*.txt") or a list of file paths to combine multiple files. Most common compression formats (GZip, BZip, etc.) are supported transparently, so you can read compressed files directly. Use blocksize (bytes) to control partitioning for parallelism.
What should I do if I hit a UnicodeDecodeError when reading text?By default, read_text assumes UTF-8. If you see UnicodeDecodeError during a compute (for example, raw_bag.count().compute()), your file is likely encoded differently. Specify the correct encoding via encoding=... (e.g., "cp1252" for many Windows-encoded files). You may need to try a few encodings or confirm with the data provider.
How can I turn a single large text file into a Bag of structured review objects without loading everything into memory?Stream the file in binary mode and locate record boundaries (e.g., two newlines “\n\n” between reviews). Record the start byte and length for each review by scanning with a moving buffer. Then distribute these byte ranges using bag.from_sequence(list_of_ranges) and map a parser that seeks, reads, decodes, and splits each chunk into key–value pairs (dict). This approach keeps memory use low and parallelizes parsing.
How do map and filter work on Bags, and are Bags mutable?- map(func) applies a Python function to every element, returning a transformed Bag (lazy). - filter(predicate) keeps elements for which predicate(element) is True. - Bags are immutable; transformations create new Bags. Even if your function appears to “modify” a dict, the original Bag’s elements remain unchanged.
How can I label reviews as positive or negative and compute aggregates like the mean score?Map a function that reads review/score, casts to float, and adds a new sentiment label (e.g., score > 3 → “positive”, else “negative”). Then map(get_score) to produce a Bag of floats and call .mean() to aggregate. Remember: the labeling step returns a new Bag; the original Bag is unchanged unless you keep the transformed one.
How do I filter out unhelpful reviews using the “review/helpfulness” field?Parse the field like "helpful/total" into numbers. Define a predicate that returns True when total > 0 and helpful/total exceeds a threshold (e.g., > 0.75). Use reviews.filter(is_helpful). You can compare aggregates (mean score, mean text length) between helpful and unhelpful subsets by mapping your metric function and calling .mean().
What is foldby, and how is it different from a reduce (e.g., mean)?Reduce operations aggregate the entire Bag to a single value (e.g., mean of all scores). foldby groups first, then reduces within each group: foldby(key, binop, init, combine, init2). - key: returns the group key (e.g., review score). - binop(acc, element): per-partition aggregation (e.g., increment count). - combine(total1, total2): merges partition results. Use foldby to get counts by score, frequencies by token, etc.
How do I convert a Bag into a DataFrame or Array for statistical analysis?If each Bag element is a fixed-length tuple or dict, you can call .to_dataframe(meta={col: dtype, ...}) to get a Dask DataFrame. From there, use DataFrame methods like .describe(). For purely numeric, homogeneously shaped data, you can also build a Dask Array and use dask.array.stats functions.
How can I run parallel text analysis with NLTK on a Bag (e.g., bigram frequencies)?- Extract and lowercase text: reviews.map(lambda r: r['review/text'].lower()) - Tokenize (e.g., RegexpTokenizer) and remove stopwords. - Create bigrams per review (nltk.bigrams(tokens)). - Flatten the nested structure with .flatten() to get a Bag of all bigrams. - Count frequencies with foldby(lambda x: x, count, 0, combine, 0) and get top-k with .topk(k, key=lambda t: t[1]). If noisy tokens (e.g., “br”, “amazon”, “http”) appear, union them into your stopword set and rerun.

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