Robust and fast topic models with sentence-transformers.
122
stars
842
commits
Python
primary language
Aug 28, 2026
updated
Topic modeling is your turf too.
Contextual topic models with representations from transformers.
| SOTA Transformer-based Topic Models | :compass: S³, :key: KeyNMF, :gem: GMM, 🗻 Topeax, 🌀 SensTopic, Clustering Models (BERTopic and Top2Vec), Autoencoding models (ZeroShotTM and CombinedTM), FASTopic |
| Models for all Scenarios | :chart_with_upwards_trend: Dynamic, :ocean: Online, :herb: Seeded, :evergreen_tree: Hierarchical, and :camera: Multimodal topic modeling |
| Easy Interpretation | :bookmark_tabs: Pretty Printing, :bar_chart: Interactive Figures, :art: topicwizard compatible |
| Topic Analysis | :robot: LLM-generated names and descriptions, :wave: Manual Topic Naming |
| Informative Topic Descriptions | :key: Keyphrases, Noun-phrases, Lemmatization, Stemming |
For more details on a particular topic, you can consult our documentation page:
| :house: Build and Train Topic Models | :art: Explore, Interpret and Visualize your Models | :wrench: Modify and Fine-tune Topic Models |
| :pushpin: Choose the Right Model for your Use-Case | :chart_with_upwards_trend: Explore Topics Changing over Time | :newspaper: Use Phrases or Lemmas for Topic Models |
| :ocean: Extract Topics from a Stream of Documents | :evergreen_tree: Find Hierarchical Order in Topics | :whale: Name Topics with Large Language Models |
Turftopic can be installed from PyPI.
pip install turftopic
If you intend to use CTMs, make sure to install the package with Pyro as an optional dependency.
pip install "turftopic[pyro-ppl]"
If you want to use clustering models like BERTopic or Top2Vec, install:
pip install "turftopic[umap-learn]"
Turftopic's models follow the scikit-learn API conventions, and as such they are quite easy to use if you are familiar with scikit-learn workflows.
Here's an example of how you use KeyNMF, one of our models on the 20Newsgroups dataset from scikit-learn.
If you are using a Mac, you might have to install the required SSL certificates on your system in order to be able to download the dataset.
from sklearn.datasets import fetch_20newsgroups
newsgroups = fetch_20newsgroups(
subset="all",
remove=("headers", "footers", "quotes"),
)
corpus: list[str] = newsgroups.data
print(len(corpus)) # 18846
Turftopic also comes with interpretation tools that make it easy to display and understand your results.
from turftopic import KeyNMF
model = KeyNMF(20)
document_topic_matrix = model.fit_transform(corpus)
Turftopic comes with a number of pretty printing utilities for interpreting the models.
To see the highest the most important words for each topic, use the print_topics() method.
model.print_topics()
| Topic ID | Top 10 Words |
|---|---|
| 0 | armenians, armenian, armenia, turks, turkish, genocide, azerbaijan, soviet, turkey, azerbaijani |
| 1 | sale, price, shipping, offer, sell, prices, interested, 00, games, selling |
| 2 | christians, christian, bible, christianity, church, god, scripture, faith, jesus, sin |
| 3 | encryption, chip, clipper, nsa, security, secure, privacy, encrypted, crypto, cryptography |
| .... |
# Print highest ranking documents for topic 0
model.print_representative_documents(0, corpus, document_topic_matrix)
| Document | Score |
|---|---|
| Poor 'Poly'. I see you're preparing the groundwork for yet another retreat from your... | 0.40 |
| Then you must be living in an alternate universe. Where were they? An Appeal to Mankind During the... | 0.40 |
| It is 'Serdar', 'kocaoglan'. Just love it. Well, it could be your head wasn't screwed on just right... | 0.39 |
model.print_topic_distribution(
"I think guns should definitely banned from all public institutions, such as schools."
)
| Topic name | Score |
|---|---|
| 7_gun_guns_firearms_weapons | 0.05 |
| 17_mail_address_email_send | 0.00 |
| 3_encryption_chip_clipper_nsa | 0.00 |
| 19_baseball_pitching_pitcher_hitter | 0.00 |
| 11_graphics_software_program_3d | 0.00 |
Turftopic now allows you to automatically assign human readable names to topics using LLMs or n-gram retrieval!
You will need to
pip install "turftopic[openai]"for this to work.
from turftopic import KeyNMF
from turftopic.analyzers import OpenAIAnalyzer
model = KeyNMF(10).fit(corpus)
namer = OpenAIAnalyzer("gpt-4o-mini")
model.rename_topics(namer)
model.print_topics()
| Topic ID | Topic Name | Highest Ranking |
|---|---|---|
| 0 | Operating Systems and Software | windows, dos, os, ms, microsoft, unix, nt, memory, program, apps |
| 1 | Atheism and Belief Systems | atheism, atheist, atheists, belief, religion, religious, theists, beliefs, believe, faith |
| 2 | Computer Architecture and Performance | motherboard, ram, memory, cpu, bios, isa, speed, 486, bus, performance |
| 3 | Storage Technologies | disk, drive, scsi, drives, disks, floppy, ide, dos, controller, boot |
| ... |
You can use a set of custom vectorizers for topic modeling over phrases, as well as lemmata and stems.
You will need to
pip install "turftopic[spacy]"for this to work.
from turftopic import BERTopic
from turftopic.vectorizers.spacy import NounPhraseCountVectorizer
model = BERTopic(
n_components=10,
vectorizer=NounPhraseCountVectorizer("en_core_web_sm"),
)
model.fit(corpus)
model.print_topics()
| Topic ID | Highest Ranking |
|---|---|
| ... | |
| 3 | fanaticism, theism, fanatism, all fanatism, theists, strong theism, strong atheism, fanatics, precisely some theists, all theism |
| 4 | religion foundation darwin fish bumper stickers, darwin fish, atheism, 3d plastic fish, fish symbol, atheist books, atheist organizations, negative atheism, positive atheism, atheism index |
| ... |
Turftopic comes with a number of visualization and pretty printing utilities for specific models and specific contexts, such as hierarchical or dynamic topic modelling. You will find an overview of these in the Interpreting and Visualizing Models section of our documentation.
pip install "turftopic[datamapplot, openai]"
from turftopic import ClusteringTopicModel
from turftopic.analyzers import OpenAIAnalyzer
model = ClusteringTopicModel(feature_importance="centroid").fit(corpus)
namer = OpenAIAnalyzer("gpt-5-nano")
model.rename_topics(namer)
fig = model.plot_clusters_datamapplot()
fig.show()
In addition, Turftopic is natively supported in topicwizard, an interactive topic model visualization library, is compatible with all models from Turftopic.
pip install "turftopic[topic-wizard]"
By far the easiest way to visualize your models for interpretation is to launch the topicwizard web app.
import topicwizard
topicwizard.visualize(corpus, model=model)
Screenshot of the topicwizard Web Application
Alternatively you can use the Figures API in topicwizard for individual HTML figures.
Please cite us when using Turftopic:
@article{
Kardos2025,
title = {Turftopic: Topic Modelling with Contextual Representations from Sentence Transformers},
doi = {10.21105/joss.08183},
url = {https://doi.org/10.21105/joss.08183},
year = {2025},
publisher = {The Open Journal},
volume = {10},
number = {111},
pages = {8183},
author = {Kardos, Márton and Enevoldsen, Kenneth C. and Kostkan, Jan and Kristensen-McLachlan, Ross Deans and Rocca, Roberta},
journal = {Journal of Open Source Software}
}
Python
87.6%
TeX
7.1%
Typst
5.3%
Robust and fast topic models with sentence-transformers.
122
stars
842
commits
Python
primary language
Aug 28, 2026
updated
Topic modeling is your turf too.
Contextual topic models with representations from transformers.
| SOTA Transformer-based Topic Models | :compass: S³, :key: KeyNMF, :gem: GMM, 🗻 Topeax, 🌀 SensTopic, Clustering Models (BERTopic and Top2Vec), Autoencoding models (ZeroShotTM and CombinedTM), FASTopic |
| Models for all Scenarios | :chart_with_upwards_trend: Dynamic, :ocean: Online, :herb: Seeded, :evergreen_tree: Hierarchical, and :camera: Multimodal topic modeling |
| Easy Interpretation | :bookmark_tabs: Pretty Printing, :bar_chart: Interactive Figures, :art: topicwizard compatible |
| Topic Analysis | :robot: LLM-generated names and descriptions, :wave: Manual Topic Naming |
| Informative Topic Descriptions | :key: Keyphrases, Noun-phrases, Lemmatization, Stemming |
For more details on a particular topic, you can consult our documentation page:
| :house: Build and Train Topic Models | :art: Explore, Interpret and Visualize your Models | :wrench: Modify and Fine-tune Topic Models |
| :pushpin: Choose the Right Model for your Use-Case | :chart_with_upwards_trend: Explore Topics Changing over Time | :newspaper: Use Phrases or Lemmas for Topic Models |
| :ocean: Extract Topics from a Stream of Documents | :evergreen_tree: Find Hierarchical Order in Topics | :whale: Name Topics with Large Language Models |
Turftopic can be installed from PyPI.
pip install turftopic
If you intend to use CTMs, make sure to install the package with Pyro as an optional dependency.
pip install "turftopic[pyro-ppl]"
If you want to use clustering models like BERTopic or Top2Vec, install:
pip install "turftopic[umap-learn]"
Turftopic's models follow the scikit-learn API conventions, and as such they are quite easy to use if you are familiar with scikit-learn workflows.
Here's an example of how you use KeyNMF, one of our models on the 20Newsgroups dataset from scikit-learn.
If you are using a Mac, you might have to install the required SSL certificates on your system in order to be able to download the dataset.
from sklearn.datasets import fetch_20newsgroups
newsgroups = fetch_20newsgroups(
subset="all",
remove=("headers", "footers", "quotes"),
)
corpus: list[str] = newsgroups.data
print(len(corpus)) # 18846
Turftopic also comes with interpretation tools that make it easy to display and understand your results.
from turftopic import KeyNMF
model = KeyNMF(20)
document_topic_matrix = model.fit_transform(corpus)
Turftopic comes with a number of pretty printing utilities for interpreting the models.
To see the highest the most important words for each topic, use the print_topics() method.
model.print_topics()
| Topic ID | Top 10 Words |
|---|---|
| 0 | armenians, armenian, armenia, turks, turkish, genocide, azerbaijan, soviet, turkey, azerbaijani |
| 1 | sale, price, shipping, offer, sell, prices, interested, 00, games, selling |
| 2 | christians, christian, bible, christianity, church, god, scripture, faith, jesus, sin |
| 3 | encryption, chip, clipper, nsa, security, secure, privacy, encrypted, crypto, cryptography |
| .... |
# Print highest ranking documents for topic 0
model.print_representative_documents(0, corpus, document_topic_matrix)
| Document | Score |
|---|---|
| Poor 'Poly'. I see you're preparing the groundwork for yet another retreat from your... | 0.40 |
| Then you must be living in an alternate universe. Where were they? An Appeal to Mankind During the... | 0.40 |
| It is 'Serdar', 'kocaoglan'. Just love it. Well, it could be your head wasn't screwed on just right... | 0.39 |
model.print_topic_distribution(
"I think guns should definitely banned from all public institutions, such as schools."
)
| Topic name | Score |
|---|---|
| 7_gun_guns_firearms_weapons | 0.05 |
| 17_mail_address_email_send | 0.00 |
| 3_encryption_chip_clipper_nsa | 0.00 |
| 19_baseball_pitching_pitcher_hitter | 0.00 |
| 11_graphics_software_program_3d | 0.00 |
Turftopic now allows you to automatically assign human readable names to topics using LLMs or n-gram retrieval!
You will need to
pip install "turftopic[openai]"for this to work.
from turftopic import KeyNMF
from turftopic.analyzers import OpenAIAnalyzer
model = KeyNMF(10).fit(corpus)
namer = OpenAIAnalyzer("gpt-4o-mini")
model.rename_topics(namer)
model.print_topics()
| Topic ID | Topic Name | Highest Ranking |
|---|---|---|
| 0 | Operating Systems and Software | windows, dos, os, ms, microsoft, unix, nt, memory, program, apps |
| 1 | Atheism and Belief Systems | atheism, atheist, atheists, belief, religion, religious, theists, beliefs, believe, faith |
| 2 | Computer Architecture and Performance | motherboard, ram, memory, cpu, bios, isa, speed, 486, bus, performance |
| 3 | Storage Technologies | disk, drive, scsi, drives, disks, floppy, ide, dos, controller, boot |
| ... |
You can use a set of custom vectorizers for topic modeling over phrases, as well as lemmata and stems.
You will need to
pip install "turftopic[spacy]"for this to work.
from turftopic import BERTopic
from turftopic.vectorizers.spacy import NounPhraseCountVectorizer
model = BERTopic(
n_components=10,
vectorizer=NounPhraseCountVectorizer("en_core_web_sm"),
)
model.fit(corpus)
model.print_topics()
| Topic ID | Highest Ranking |
|---|---|
| ... | |
| 3 | fanaticism, theism, fanatism, all fanatism, theists, strong theism, strong atheism, fanatics, precisely some theists, all theism |
| 4 | religion foundation darwin fish bumper stickers, darwin fish, atheism, 3d plastic fish, fish symbol, atheist books, atheist organizations, negative atheism, positive atheism, atheism index |
| ... |
Turftopic comes with a number of visualization and pretty printing utilities for specific models and specific contexts, such as hierarchical or dynamic topic modelling. You will find an overview of these in the Interpreting and Visualizing Models section of our documentation.
pip install "turftopic[datamapplot, openai]"
from turftopic import ClusteringTopicModel
from turftopic.analyzers import OpenAIAnalyzer
model = ClusteringTopicModel(feature_importance="centroid").fit(corpus)
namer = OpenAIAnalyzer("gpt-5-nano")
model.rename_topics(namer)
fig = model.plot_clusters_datamapplot()
fig.show()
In addition, Turftopic is natively supported in topicwizard, an interactive topic model visualization library, is compatible with all models from Turftopic.
pip install "turftopic[topic-wizard]"
By far the easiest way to visualize your models for interpretation is to launch the topicwizard web app.
import topicwizard
topicwizard.visualize(corpus, model=model)
Screenshot of the topicwizard Web Application
Alternatively you can use the Figures API in topicwizard for individual HTML figures.
Please cite us when using Turftopic:
@article{
Kardos2025,
title = {Turftopic: Topic Modelling with Contextual Representations from Sentence Transformers},
doi = {10.21105/joss.08183},
url = {https://doi.org/10.21105/joss.08183},
year = {2025},
publisher = {The Open Journal},
volume = {10},
number = {111},
pages = {8183},
author = {Kardos, Márton and Enevoldsen, Kenneth C. and Kostkan, Jan and Kristensen-McLachlan, Ross Deans and Rocca, Roberta},
journal = {Journal of Open Source Software}
}
Python
87.6%
TeX
7.1%
Typst
5.3%