Skip to main content

PolarsGrouper

PolarsGrouper is a Rust-based extension for Polars that provides efficient graph analysis capabilities, with a focus on component grouping and network analysis.

Core Features

Component Grouping

  • super_merger: Easy-to-use wrapper for grouping connected components
  • super_merger_weighted: Component grouping with weight thresholds
  • Efficient implementation using Rust and Polars
  • Works with both eager and lazy Polars DataFrames

Hierarchy / BOM Explosion

  • hierarchy_totals, hierarchy_levels, hierarchy_paths: explode a parent → child edge list (bill of materials, chart of accounts, WBS) into its transitive closure, with quantities rolled up along every path
  • Replaces WITH RECURSIVE / CONNECT BY queries and for-loops, and runs inside lazy queries

Additional Graph Analytics

  • Shortest Path Analysis: Find shortest paths between nodes
  • PageRank: Calculate node importance scores
  • Betweenness Centrality: Identify key bridge nodes
  • Association Rules: Discover item relationships and patterns

Installation

pip install polars-grouper

# For development:
python -m venv .venv
source .venv/bin/activate
maturin develop

Usage Examples

Basic Component Grouping

The core functionality uses super_merger to identify connected components:

import polars as pl
from polars_grouper import super_merger

df = pl.DataFrame({
    "from": ["A", "B", "C", "D", "E", "F"],
    "to": ["B", "C", "A", "E", "F", "D"],
    "value": [1, 2, 3, 4, 5, 6]
})

result = super_merger(df, "from", "to")
print(result)

Weighted Component Grouping

For cases where edge weights matter:

from polars_grouper import super_merger_weighted

df = pl.DataFrame({
    "from": ["A", "B", "C", "D", "E"],
    "to": ["B", "C", "D", "E", "A"],
    "weight": [0.9, 0.2, 0.05, 0.8, 0.3]
})

result = super_merger_weighted(
    df, 
    "from", 
    "to", 
    "weight",
    weight_threshold=0.3
)
print(result)

Hierarchy / BOM Explosion

Resolve a bill of materials in one lazy expression. Quantities multiply along a path (4 wheels × 5 screws) and add up across paths (+ 20 screws directly on the car):

import polars as pl
from polars_grouper import hierarchy_totals, hierarchy_levels, hierarchy_paths

bom = pl.LazyFrame({
    "parent": ["car", "car", "car", "wheel", "wheel", "wheel", "rim"],
    "child": ["wheel", "steering_wheel", "screw", "tyre", "rim", "screw", "iron"],
    "qty": [4.0, 1.0, 20.0, 1.0, 1.0, 5.0, 2.5],
})

totals = bom.select(hierarchy_totals("parent", "child", "qty").alias("bom")).unnest("bom")

# Raw materials needed for one car
totals.filter(pl.col("ancestor") == "car", pl.col("is_leaf")).collect()
# ┌──────────┬────────────────┬───────┬──────────┬─────────┐
# │ ancestor ┆ descendant     ┆ level ┆ quantity ┆ is_leaf │
# ╞══════════╪════════════════╪═══════╪══════════╪═════════╡
# │ car      ┆ steering_wheel ┆ 1     ┆ 1.0      ┆ true    │
# │ car      ┆ screw          ┆ 1     ┆ 40.0     ┆ true    │
# │ car      ┆ tyre           ┆ 2     ┆ 4.0      ┆ true    │
# │ car      ┆ iron           ┆ 3     ┆ 10.0     ┆ true    │
# └──────────┴────────────────┴───────┴──────────┴─────────┘

Three functions, one per level of detail. They share column names, so each is an aggregation of the next:

function one row per extra columns
hierarchy_totals ancestor, descendant level is the shallowest level
hierarchy_levels ancestor, descendant, level
hierarchy_paths path (an indented BOM) parent, quantity_per, path

All three take top_level_only (explode finished products only), include_self (add a level-0 row per node) and max_depth. A cycle in the data raises an error that names it.

The same works for any hierarchy. To roll up general-ledger balances along a chart of accounts, link every account to itself and to everything below it, then aggregate:

closure = accounts.select(
    hierarchy_totals("parent_account", "account", include_self=True).alias("closure")
).unnest("closure")

balances = (
    closure.join(transactions, left_on="descendant", right_on="account")
    .group_by("ancestor")
    .agg(pl.col("amount").sum())
)

Additional Graph Analytics

Shortest Path Analysis

Find shortest paths between nodes:

from polars_grouper import calculate_shortest_path

df = pl.DataFrame({
    "from": ["A", "A", "B", "C"],
    "to": ["B", "C", "C", "D"],
    "weight": [1.0, 2.0, 1.0, 1.5]
})

paths = df.select(
    calculate_shortest_path(
        pl.col("from"),
        pl.col("to"),
        pl.col("weight"),
        directed=False
    ).alias("paths")
).unnest("paths")

PageRank Calculation

Calculate node importance:

from polars_grouper import page_rank

df = pl.DataFrame({
    "from": ["A", "A", "B", "C", "D"],
    "to": ["B", "C", "C", "A", "B"]
})

rankings = df.select(
    page_rank(
        pl.col("from"),
        pl.col("to"),
        damping_factor=0.85
    ).alias("pagerank")
).unnest("pagerank")

Association Rule Mining

Discover item relationships:

from polars_grouper import graph_association_rules

transactions = pl.DataFrame({
    "transaction_id": [1, 1, 1, 2, 2, 3],
    "item_id": ["A", "B", "C", "B", "D", "A"],
    "frequency": [1, 2, 1, 1, 1, 1]
})

rules = transactions.select(
    graph_association_rules(
        pl.col("transaction_id"),
        pl.col("item_id"),
        pl.col("frequency"),
        min_support=0.1
    ).alias("rules")
).unnest("rules")

Betweenness Centrality

Identify bridge nodes:

from polars_grouper import betweenness_centrality

df = pl.DataFrame({
    "from": ["A", "A", "B", "C", "D", "E"],
    "to": ["B", "C", "C", "D", "E", "A"]
})

centrality = df.select(
    betweenness_centrality(
        pl.col("from"),
        pl.col("to"),
        normalized=True
    ).alias("centrality")
).unnest("centrality")

Performance

The library is implemented in Rust for high performance:

  • Efficient memory usage
  • Fast computation for large graphs
  • Seamless integration with Polars' lazy evaluation

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Metadata

Release files for polars-grouper 0.6.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for polars-grouper 0.6.1
File Size Uploaded
polars_grouper-0.6.1.tar.gz 55.8 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for polars-grouper 0.6.1
File
polars_grouper-0.6.1-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details
polars_grouper-0.6.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details
polars_grouper-0.6.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-32 Details
polars_grouper-0.6.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details
polars_grouper-0.6.1-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details
polars_grouper-0.6.1-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details

Total release size: 30.4 MB

Release files / polars_grouper-0.6.1.tar.gz

Download URL polars_grouper-0.6.1.tar.gz
Size 55.8 kB
Tags Source
SHA-256 checksum
How to use checksums
5351d492022846977373050a9fc65360560b9e4b57e10fb06dc940218a58ac0e
BLAKE2b-256 checksum
How to use checksums
5534e7534e344830a47e9336dcedfda6daa885696e20a806c6c50ea98644c7a6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / polars_grouper-0.6.1-cp310-abi3-win_amd64.whl

Download URL polars_grouper-0.6.1-cp310-abi3-win_amd64.whl
Size 4.7 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
0d51f4da9d58995edcce41f6d88ca459e50543ee28438befb39ed6f141ef2596
BLAKE2b-256 checksum
How to use checksums
79fce6bb9fc0ed376c31cb59a1008f6c5cd7712d5e0ce2e1e9cde8ca4fe104e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / polars_grouper-0.6.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL polars_grouper-0.6.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 5.3 MB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
cb26fc6082dfa05a31e8ccb753b2a7b9bbc9c38b83719d48896ffcec70bdf891
BLAKE2b-256 checksum
How to use checksums
5b8ff21a1c620e09c2f20ba863eb16ed14e05243a20c5659b5aa4bfa475472c9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / polars_grouper-0.6.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl

Download URL polars_grouper-0.6.1-cp310-abi3-manylinux_2_17_i686.manylinux2014_i686.whl
Size 6.1 MB
Tags CPython 3.10 Linux glibc 2.17+ x86-32 abi3
SHA-256 checksum
How to use checksums
32d9e9e6b475edd2b40f3cc7c58f75dcaee6391d400c6fcc0c3ad95b5e9a2f66
BLAKE2b-256 checksum
How to use checksums
7ee558788476d20d3787a7d9f089176300c14294eb64d22f4b383066264e7cea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / polars_grouper-0.6.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL polars_grouper-0.6.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 5.3 MB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
898a43958c6c71bdb05597b6f8aeb53c8120b93443314c13f52ac42eb19d8526
BLAKE2b-256 checksum
How to use checksums
a180c0e9a725e6c9171ce87a8a463aadea071c4cd6f0698aef93339a93abdcb1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / polars_grouper-0.6.1-cp310-abi3-macosx_11_0_arm64.whl

Download URL polars_grouper-0.6.1-cp310-abi3-macosx_11_0_arm64.whl
Size 4.4 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
b99a7d1779ee3c38a246e1406b0413498ed4a29637fc7e77a331b3e682e0b391
BLAKE2b-256 checksum
How to use checksums
727f9ed412c87bd0499ddc6f9e4fe7aacc5890bc30821503a85868c3a19a4298
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / polars_grouper-0.6.1-cp310-abi3-macosx_10_12_x86_64.whl

Download URL polars_grouper-0.6.1-cp310-abi3-macosx_10_12_x86_64.whl
Size 4.6 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
39a5bb8d5ca474aba3f5a893e72775a6bbd59c3f30008388a18f5fe27a41b3bf
BLAKE2b-256 checksum
How to use checksums
0b741d98c4082115393d139197c312ea3d7baadf9de22917b42245654fcbe265
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release history Release notifications | RSS feed

This release

0.6.1 This release

7 release files

0.6.0

6 release files

0.5.0

6 release files

0.4.0

8 release files

0.3.0

6 release files

0.2.0

6 release files

0.1.0

6 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page