SEJ Semantic Keyword Clustering
Use cases
Groups keywords into topical clusters using the sentence-transformers community_detection algorithm, iterating until no new clusters form.
The Colab notebook uses all-MiniLM-L6-v2 with configurable cluster accuracy (default 85%) and minimum cluster size (default 2).
The Python script uses paraphrase-MiniLM-L3-v2 with a fixed 0.75 threshold.
Both rename each cluster to the shortest keyword in the group.
Featured in Search Engine Journal.
Platform
Python script (requires Python 3.x)
Input
Keywords CSV with a Keyword column (the Colab notebook auto-maps query, Search term, and Top queries; the Python script requires a Keyword column)
Output
CSV with Cluster Name column prepended, clusters named after the shortest keyword, unclustered rows labelled zzz_no_cluster. Applies to the Colab notebook; the standalone script's final CSV write fails as published due to a broken output path.
Features
- sentence-transformers community_detection clustering (batch_size 256)
- Colab notebook: configurable accuracy 0-100 (default 85) and min_community_size (default 2)
- Python script: paraphrase-MiniLM-L3-v2 model, fixed 0.75 threshold and min cluster size 2
- Iterative clustering loop until no new clusters form
- Renames each cluster to its shortest keyword; unclustered rows labelled zzz_no_cluster
- Notebook: encoding detection via BOM check with chardet fallback
- Notebook: delimiter auto-detection via the detect_delimiter library
- Notebook: warns above 50,000 rows (crash risk in Colab)
How to use
- 1 Notebook: upload a keyword CSV (common keyword column names auto-renamed to Keyword)
- 2 Script: place one CSV in the working directory with a column named Keyword
- 3 Set cluster accuracy and minimum cluster size (notebook only)
- 4 Run the clustering process (iterates until stable)
- 5 Notebook: download Your Keywords Clustered.csv with Cluster Name prepended
Frequently asked questions
- What does my keyword column need to be called?
- The Colab notebook expects a column named 'Keyword' but automatically renames common variants first: query, Search term, Top queries, queries, Keywords, keywords and Search terms report all get mapped. The standalone Python script shows a column picker, but a later merge step is hardcoded to a column called 'Keyword', so in the script your keyword column must literally be named Keyword or the merge fails.
- What do cluster accuracy and minimum cluster size actually control?
- Cluster accuracy is divided by 100 and used as the cosine similarity threshold for sentence-transformers community_detection, so the default 85 means keywords need 0.85 similarity to group. Minimum cluster size (default 2) is the smallest group allowed. Raising accuracy gives tighter clusters but pushes more keywords into zzz_no_cluster. The Python script has no settings: it is fixed at 0.75 similarity with a minimum size of 2.
- Why does the clustering loop run multiple passes?
- After each pass, clustered keywords are removed and community detection re-runs on only the leftovers, repeating until a pass creates no new clusters. This lets keywords that narrowly missed a large cluster form smaller clusters of their own in later passes, so total runtime depends on how many passes are needed, not just keyword count.
- What does zzz_no_cluster mean in the output?
- Any keyword that never reached a community of at least the minimum cluster size ends up labelled zzz_no_cluster. The zzz prefix is deliberate so unclustered rows sort to the bottom of the CSV. The notebook also prints the percentage of rows clustered successfully at the end, which is your signal to relax the accuracy setting if too much is left over.
- Which embedding model is used and can I change it?
- The notebook defaults to all-MiniLM-L6-v2, with a commented-out option for all-mpnet-base-v2, which the code notes gives the best quality at roughly five times slower. The Python script uses the smaller paraphrase-MiniLM-L3-v2. Either can be swapped by editing the transformer variable to any pretrained model from sbert.net.
Want me to run this for you?
I run this tool as a managed service, or build something custom around your data. You get the insights without touching the code.
Related Tools
Convert marketing-heavy H1 headings into clean, natural search queries using Claude.
Suggest a cleaner representative keyword for each keyword using an LLM.
Visualise tagged keyword CSVs as interactive D3.js zoomable circle packing charts.
Tag keywords using substring matching against up to 7 classification columns.
Two-level eBay related search scraping with ECharts tree visualisations.
Preview how your page will appear in Google search results.
Need something built for your business?
This tool started as bespoke client work. I build custom scripts, data pipelines, and full apps for SEO and product data problems that off-the-shelf tools don't solve.
Tell Me What You Need