Item Binning
Algorithm
Itertools
Numpy
Efficiency

Efficient item binning algorithm itertools/numpy

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Item binning problems appear in analytics, simulation, and preprocessing pipelines where raw values must be grouped efficiently. Python offers two strong tools for this work, itertools for streaming friendly grouping and NumPy for vectorized numeric bucketing. Choosing between them depends on data size, memory limits, and whether bins are category based or range based.

Define Binning Goal Before Coding

Binning can mean at least three different tasks. First is grouping equal keys such as category labels. Second is mapping continuous values into numeric ranges. Third is balancing items across fixed capacity bins. Each variant has different complexity and data structures.

For category grouping in sorted streams, itertools.groupby is concise and memory efficient.

python
1from itertools import groupby
2
3items = ["a", "a", "b", "b", "b", "c"]
4for key, group in groupby(items):
5    values = list(group)
6    print(key, len(values), values)

Remember that groupby only groups consecutive values, so sort first when needed.

Fast Numeric Range Binning With NumPy

For numeric arrays, NumPy operations avoid Python loops and scale well.

python
1import numpy as np
2
3values = np.array([1.2, 2.8, 3.1, 4.9, 5.0, 7.3])
4edges = np.array([0, 2, 4, 6, 8])
5
6# Bin index in interval map
7bin_ids = np.digitize(values, edges, right=False) - 1
8print(bin_ids)
9
10# Count items per bin
11counts = np.bincount(bin_ids, minlength=len(edges) - 1)
12print(counts)

This is efficient for large arrays and works nicely with downstream vectorized statistics.

Capacity Based Binning With Greedy Strategy

If each item has weight and bins have max capacity, a simple greedy heuristic gives a practical baseline.

python
1from typing import List
2
3def first_fit(weights: List[int], capacity: int):
4    bins = []
5    for w in weights:
6        placed = False
7        for b in bins:
8            if sum(b) + w <= capacity:
9                b.append(w)
10                placed = True
11                break
12        if not placed:
13            bins.append([w])
14    return bins
15
16print(first_fit([4, 8, 1, 4, 2, 1], capacity=10))

This approach is not always optimal, but it is easy to implement and often good enough for operational workloads.

Optimize for Throughput and Memory

For very large datasets, avoid materializing intermediate Python lists repeatedly. Prefer vectorized arrays, preallocated outputs, and chunked processing. If input arrives as stream events, itertools can keep memory bounded while maintaining good readability.

Benchmark with representative data, not tiny examples. A method that looks fast on one thousand rows can degrade at fifty million rows because allocation patterns dominate runtime.

Benchmark and Validate Binning Output

Performance tuning without correctness checks is risky. Create reference output from a simple implementation, then compare optimized versions. Use timing and memory measurements together to avoid one sided optimization.

python
1import time
2import numpy as np
3
4rng = np.random.default_rng(42)
5values = rng.normal(size=5_000_000)
6edges = np.array([-3, -1, 0, 1, 3])
7
8start = time.perf_counter()
9ids = np.digitize(values, edges)
10counts = np.bincount(ids, minlength=len(edges) + 1)
11elapsed = time.perf_counter() - start
12
13print("elapsed", round(elapsed, 3), "seconds")
14print("counts", counts[:6])

For production pipelines, keep a small regression dataset and assert that bin counts stay stable after refactors.

Common Pitfalls

  • Using groupby on unsorted data and expecting global grouping.
  • Building Python loops for numeric binning when vectorized NumPy is available.
  • Ignoring edge inclusion rules in digitize, causing off by one bin errors.
  • Choosing greedy packing when exact optimal assignment is required.
  • Measuring only runtime and ignoring peak memory in large batch jobs.

Summary

  • Clarify binning type first, category, range, or capacity based.
  • Use itertools.groupby for sorted stream grouping.
  • Use NumPy vectorized functions for large numeric binning tasks.
  • Apply greedy capacity algorithms when exact optimization is unnecessary.
  • Validate edge rules and benchmark on realistic data volumes.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.