Detect Communities in NetworkX Using the Louvain Method
Find natural groups in an undirected graph with NetworkX's Louvain implementation, verify modularity, and account for non-deterministic results.
29 Jan 2026, 21:43 UTC

Problem: Connected components are too coarse for real networks
When you need to find natural groups in a graph, connected components often split too loosely or not at all. A single component can contain many distinct social, functional, or topical clusters. The Louvain method addresses this by optimizing modularity, a score that measures how densely nodes are connected within groups compared to between groups.
Useful takeaway
Use networkx.algorithms.community.louvain_communities() on an undirected graph in NetworkX 3.0 or later. Treat the result as one valid partition among several possible ones, and verify it with modularity and repeated runs.
Prerequisites
- Python 3.x
- NetworkX 3.0 or later
- An undirected graph (
nx.Graph, notnx.DiGraph)
Check the installed version in a terminal with normal user permissions. No administrator access is required:
python3 -c 'import networkx as nx; print(nx.__version__)'
If the version is below 3.0, upgrade NetworkX before using the built-in community module.
Procedure: Detect and evaluate communities
1. Import and build the graph
import networkx as nx
from networkx.algorithms import community
# Example: Zachary's karate club graph
G = nx.karate_club_graph()
Replace the example graph with your own data. The Louvain method expects an undirected graph. If your graph is directed, convert it first:
G = G.to_undirected()
2. Run community detection
communities = community.louvain_communities(G)
The function returns a list of sets. Each set contains the node identifiers belonging to one community.
3. Inspect the partition
print(f'Number of communities: {len(communities)}')
for i, comm in enumerate(communities, 1):
print(f'Community {i}: {sorted(comm)}')
Each set is unordered, and the list order is not meaningful. Two runs may return the same communities in a different list order. Compare partitions by node membership, not by list position.
Do not assume the same membership across runs. The algorithm uses random initialization, so the partition can change between executions on the same graph.
4. Score the partition with modularity
mod = community.modularity(G, communities)
print(f'Modularity: {mod:.4f}')
Modularity quantifies the strength of the division into communities. Higher values generally indicate stronger structure, but there is no universal cutoff. Compare modularity across candidate partitions on the same graph rather than relying on an absolute number.
5. Check stability across repeated runs
runs = [community.louvain_communities(G) for _ in range(5)]
scores = [community.modularity(G, r) for r in runs]
print(f'Modularity range: {min(scores):.4f} - {max(scores):.4f}')
A wide range suggests weak community structure or sensitivity to random initialization. If stability matters, run the detection multiple times and select the partition with the highest modularity, or report the variation.
Practical example: Karate Club graph
NetworkX includes Zachary's karate club graph, a small social network commonly used to validate community detection because it has a known split into two factions. Exact community membership from Louvain can shift between runs because of random initialization.
| Check | Command or inspection | Expected result |
|---|---|---|
| Community module imports | from networkx.algorithms import community | No ImportError |
| Version supported | nx.__version__ | 3.0 or higher |
| Function returns partition | type(communities) | List of set objects |
| Modularity is finite | community.modularity(G, communities) | Finite floating-point number |
Limitations and risks
- Non-deterministic output: Different runs can produce different communities. Do not treat one run as the definitive answer without checking stability.
- Dense graphs: Performance degrades on very dense graphs with high clustering. Consider sampling or simplification for very large networks.
- Memory usage: Scales with graph size. Monitor memory on graphs with hundreds of thousands of nodes or more.
- No guaranteed optimum: Louvain optimizes modularity heuristically. Multiple valid partitions may exist for the same graph.
Recovery and next steps
Community detection is read-only and does not modify your graph, so no rollback is needed. If results are unstable or unhelpful:
- Run the detection multiple times and compare modularity scores.
- Inspect your installed NetworkX version's signature for
louvain_communitiesto see whether weight or resolution parameters are available for your graph. - Try other algorithms in
networkx.algorithms.communityif Louvain does not produce useful partitions. - If you need a stable identifier for each community in downstream code, convert the list of sets to a dictionary mapping node to community index after selecting a partition.
Before working with real data, verify the import and version check above, then test on nx.karate_club_graph(). Confirm that communities is a list of non-empty sets and that modularity returns a finite number.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.