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.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| polars_grouper-0.7.0.tar.gz | 57.1 kB | Without provenance | Details for polars_grouper-0.7.0.tar.gz |
Built distributions (wheels)
Total release size: 30.7 MB
Release files / polars_grouper-0.7.0.tar.gz
| Download URL | polars_grouper-0.7.0.tar.gz |
|---|---|
| Size | 57.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cc8232098ae88d271f6ca492676769f181390d1dc7eac828710c7481edd5e7ee
|
|
BLAKE2b-256 checksum How to use checksums |
f5e4d3eb7223b9c414693caf3862f549f66f6018803abc4c7b291362e8b1d939
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.16.0
|
Release files / polars_grouper-0.7.0-cp310-abi3-win_amd64.whl
| Download URL | polars_grouper-0.7.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 4.7 MB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
5445038d95b93d800c7fb688cf9c9d2c51c331b368a0706712dde68b8fd41dad
|
|
BLAKE2b-256 checksum How to use checksums |
454efcfface86009dfaba048e9a5c316317c5c4910659cb62e9c56a52fbc9ac5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.16.0
|
Release files / polars_grouper-0.7.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
| Download URL | polars_grouper-0.7.0-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl |
|---|---|
| Size | 5.4 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
a2ba08827d275e4031d02c178de811c7a84707de9bfb436a0e8d61055ca643a6
|
|
BLAKE2b-256 checksum How to use checksums |
887046edf057c7d2915ad12a2e787ddeabc11a205bf6a3fea5be7daffd8036a1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.16.0
|
Release files / polars_grouper-0.7.0-cp310-abi3-manylinux2014_i686.manylinux_2_17_i686.whl
| Download URL | polars_grouper-0.7.0-cp310-abi3-manylinux2014_i686.manylinux_2_17_i686.whl |
|---|---|
| Size | 6.1 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-32 abi3 |
|
SHA-256 checksum How to use checksums |
164a7c74275bf302a14089239abe3578d5f84dd5a0c48d8bb97445f8565b2416
|
|
BLAKE2b-256 checksum How to use checksums |
2f489ba6780dac64d9cf41c8366004b2c46f7e0134cb6ecf7ee221d6477d7b63
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.16.0
|
Release files / polars_grouper-0.7.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
| Download URL | polars_grouper-0.7.0-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl |
|---|---|
| Size | 5.3 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
9fccff986798dbf08ff261093f1a54a815e982945a84ffcd43596f7608cc39a0
|
|
BLAKE2b-256 checksum How to use checksums |
6f3eb93136e14ee2ec5bd556974277efd8dbae9d1e559ec003769bd66486eb9c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.16.0
|
Release files / polars_grouper-0.7.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | polars_grouper-0.7.0-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 |
ac9195a7149fa719727d58ec86523acecdf1d07025355a43288797b45065a249
|
|
BLAKE2b-256 checksum How to use checksums |
59de96293369b557ca127473732c99d23d0c6bb02c496e1b9fb28240dba84f92
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.16.0
|
Release files / polars_grouper-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | polars_grouper-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 4.7 MB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
f479d681359970a62263e03c31facd4901e13c07b445ef99eb29a20d9fbb721d
|
|
BLAKE2b-256 checksum How to use checksums |
735587ac5812a4c2470d3a492085a7f218600493a9c03c326b2d1772225a2c9c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
maturin/1.16.0
|
Security for polars-grouper 0.7.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.