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 componentssuper_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 BYqueries 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)
| File | Size | Uploaded | |
|---|---|---|---|
| polars_grouper-0.6.1.tar.gz | 55.8 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| 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
|