Skip to content

Repository files navigation

STREAM: Simplified Topic Retrieval, Exploration, and Analysis Module

- Topic Modeling Made Easy in Python -

We present STREAM, a Simplified Topic Retrieval, Exploration, and Analysis Module for User-Friendly and Interactive Topic Modeling and Visualization. Our paper can be found here.

Table of Contents

🏃 Quick Start

Get started with STREAM in just a few lines of code:

fromstream_topic.modelsimportKmeansTMfromstream_topic.utilsimportTMDatasetdataset=TMDataset()
dataset.fetch_dataset("BBC_News")
dataset.preprocess(model_type="KmeansTM")
model=KmeansTM()
model.fit(dataset, n_topics=20)
topics=model.get_topics()
print(topics)

🚀 Installation

You can install STREAM directly from PyPI or from the GitHub repository:

  1. PyPI (Recommended):

    pip install stream-topic
  2. GitHub:

    pip install git+https://github.com/AnFreTh/STREAM.git
  3. Download necessary NLTK resources:

    To download all necessary NLTK resources required for some models, simply run:

    importnltkdefensure_nltk_resources():
    resources= [
    "stopwords",
    "wordnet",
    "punkt_tab",
    "brown",
    "averaged_perceptron_tagger"
    ]
    forresourceinresources:
    try:
    nltk.data.find(resource)
    exceptLookupError:
    try:
    print(f"Downloading NLTK resource: {resource}")
    nltk.download(resource)
    exceptExceptionase:
    print(f"Failed to download {resource}: {e}")
    ensure_nltk_resources()
  4. Install requirements for add-ons: To use STREAMS visualizations, simply run:

    pip install stream-topic[plotting]

    For BERTopic, run:

    pip install stream-topic[hdbscan]

    For DCTE:

    pip install stream-topic[dcte]

    For the experimental features:

    pip install stream-topic[experimental]

📦 Available Models

STREAM offers a variety of neural as well as non-neural topic models and we are always trying to incorporate more and new models. If you wish to incorporate your own model, or want another model incorporated please raise an issue with the required information. Currently, the following models are implemented:

NameImplementation
LDALatent Dirichlet Allocation
NMFNon-negative Matrix Factorization
WordCluTMTired of topic models?
CEDCTopics in the Haystack
DCTEHuman in the Loop
KMeansTMSimple Kmeans followed by c-tfidf
SomTMSelf organizing map followed by c-tfidf
CBCCoherence based document clustering
TNTMTransformer-Representation Neural Topic Model
ETMTopic modeling in embedding spaces
CTMCombined Topic Model
CTMNegContextualized Topic Models with Negative Sampling
ProdLDAAutoencoding Variational Inference For Topic Models
NeuralLDAAutoencoding Variational Inference For Topic Models
NSTMNeural Topic Model via Optimal Transport

📊 Available Metrics

Since evaluating topic models, especially automatically, STREAM implements numerous evaluation metrics. Especially, the intruder based metrics, while they might take some time to compute, have shown great correlation with human evaluation.

NameDescription
ISIMAverage cosine similarity of top words of a topic to an intruder word.
INTFor a given topic and a given intruder word, Intruder Accuracy is the fraction of top words to which the intruder has the least similar embedding among all top words.
ISHCalculates the shift in the centroid of a topic when an intruder word is replaced.
ExpressivityCosine Distance of topics to meaningless (stopword) embedding centroid
Embedding Topic DiversityTopic diversity in the embedding space
Embedding CoherenceCosine similarity between the centroid of the embeddings of the stopwords and the centroid of the topic.
NPMIClassical NPMi coherence computed on the source corpus.

🗂️ Available Datasets

To integrate custom datasets for modeling with STREAM, please follow the example notebook in the examples folder. For benchmarking new models, STREAM already includes the following datasets:

Name# Docs# Words# FeaturesDescription
Spotify_most_popular5,86018,19317Spotify dataset comprised of popular song lyrics and various tabular features.
Spotify_least_popular5,12420,16814Spotify dataset comprised of less popular song lyrics and various tabular features.
Spotify11,01225,83514General Spotify dataset with song lyrics and various tabular features.
Reddit_GME21,55911,7246Reddit dataset filtered for "Gamestop" (GME) from the Subreddit "r/wallstreetbets".
Stocktwits_GME300,00014,7073Stocktwits dataset filtered for "Gamestop" (GME), covering the GME short squeeze of 2021.
Stocktwits_GME_large600,00094,9250Larger Stocktwits dataset filtered for "Gamestop" (GME), covering the GME short squeeze of 2021.
Reuters10,78819,696-Preprocessed Reuters dataset.
Poliblogs13,24647,1062Preprocessed Poliblogs dataset suitable for STMs.
20NewsGroups18,84670,461-preprocessed 20NewsGroups dataset
BBC_News2,22519,116-preprocessed BBC News dataset
If you wish yo include and publish one of your datasets directly into the package, feel free to contact us.

🔧 Usage

To use one of the available models, follow the simple steps below:

  1. Import the necessary modules:

    fromstream_topic.modelsimportKmeansTMfromstream_topic.utilsimportTMDataset

🛠️ Preprocessing

  1. Get your dataset and preprocess for your model:
    dataset=TMDataset()
    dataset.fetch_dataset("20NewsGroup")
    dataset.preprocess(model_type="KmeansTM")

The specified model_type is optional and further arguments can be specified. Default steps are predefined for all included models. Steps like stopword removal and lemmatizing are automatically performed for models like e.g. LDA.

🚀 Model fitting

Fitting a model from STREAM follows a simple, sklearn-like logic and every model can be fit identically.

  1. Choose the model you want to use and train it:

    model=KmeansTM()
    model.fit(dataset, n_topics=20)

Depending on the model, check the documentation for hyperparameter settings. To get the topics, simply run:

  1. Get the topics:
    topics=model.get_topics()

✅ Evaluation

stream-topic implements various evaluation metrics, mostly focused around the intruder word task. The implemented metrics achieve high correlations with human evaluation. See here for the detailed description of the metrics.

To evaluate your model simply use one of the metrics.

fromstream_topic.metricsimportISIM, INT, ISH,Expressivity, NPMImetric=ISIM()
metric.score(topics)

Scores for each topic are available via:

metric.score_per_topic(topics)

To leverage one of the metrics available in octis, simply create a model output that fits within the octis' framework

fromoctis.evaluation_metrics.diversity_metricsimportTopicDiversitymodel_output= {"topics": model.get_topics(), "topic-word-matrix": model.get_beta(), "topic-document-matrix": model.get_theta()}
metric=TopicDiversity(topk=10) # Initialize metrictopic_diversity_score=metric.score(model_output)

Similarly to use one of STREAMS metrics for any model, use the topics and occasionally the $\beta$ (topic-word-matrix) of the model to calculate the score.

🔍 Hyperparameter optimization

If you want to optimize the hyperparameters, simply run:

model.optimize_and_fit(
dataset,
min_topics=2,
max_topics=20,
criterion="aic",
n_trials=20,
)

🖼️ Visualization

You can also specify to optimize with respect to any evaluation metric from stream_topic. Visualize the results:

fromstream_topic.visualsimportvisualize_topic_model,visualize_topicsvisualize_topic_model(
model, reduce_first=True, port=8051,
)

Figure Description

📈 Downstream Tasks

The general formulation of a Neural Additive Model (NAM) can be summarized by the equation:

$$ E(y) = h(β + ∑_{j=1}^{J} f_j(x_j)), $$

where $h(·)$ denotes the activation function in the output layer, such as a linear activation for regression tasks or softmax for classification tasks. $x ∈ R^j$ represents the input features, and $β$ is the intercept. The function $f_j : R → R$ corresponds to the Multi-Layer Perceptron (MLP) for the $j$-th feature.

Let's consider $x$ as a combination of categorical and numerical features $x_{tab}$ and document features $x_{doc}$. After applying a topic model, STREAM extracts topical prevalences from documents, effectively transforming the input into $z ≡ (x_{tab}, x_{top})$, a probability vector over documents and topics. Here, $x_{j(tab)}^{(i)}$ indicates the $j$-th tabular feature of the $i$-th observation, and $x_{k(top)}^{(i)}$ represents the $i$-th document's topical prevalence for topic $k$.

For preserving interpretability, the downstream model is defined as:

$$ h(E[y]) = β + ∑_{j=1}^{J} f_j(x_{j(tab)}) + ∑_{k=1}^{K} f_k(x_{k(top)}), $$

In this setup, visualizing the shape function k reveals the impact of a topic on the target variable y. For example, in the context of the Spotify dataset, this could illustrate how a topic influences a song's popularity.

Fitting a downstream model with a pre-trained topic model is straightforward using the PyTorch Trainer class. Subsequently, visualizing all shape functions can be done similarly to the approach described by Agarwal et al. (2021).

fromlightningimportTrainerfromstream_topic.NAMimportDownstreamModel# Instantiate the DownstreamModeldownstream_model=DownstreamModel(
trained_topic_model=topic_model,
target_column='target', # Target variabletask='regression', # or 'classification'dataset=dataset, batch_size=128,
lr=0.0005
)
# Use PyTorch Lightning's Trainer to train and validate the modeltrainer=Trainer(max_epochs=10)
trainer.fit(downstream_model)
# Plottingfromstream_topic.visualsimportplot_downstream_modelplot_downstream_model(downstream_model)

🧪 Experimental 🧪

stream-topic.experimental includes several experimental topic representations as well as new stuff we want to try out.

This includes, e.g. topic summarization:

fromstream_topic.experimentalimportstopic_summariessummaries=topic_summaries(topics, openai_key)
forsummaryinsummaries:
print(f"{summary}\n")

But also the possibility to generate a story from the created topics:

fromstream_topic.experimentalimportstory_topicstory=story_topic(topics[1], openai_key)
print(story)

Lastly, it offers the possibility to visualize your topic in a way, a movie poster could be designed:

fromstream_topic.experimentalimportmovie_postertopic= ["tiger", "lion", "cougar", "cat", "hippo", "chair", "apple", "meat", "poachers", "hyeena"]
movie_poster(topic, openai_key, return_style="plot")

This is just one of many possible visualization, but we found that to be rather coherent in terms of truly visualizing the created topics. Feel free to contribute or rais issues fo further experimental ideas.

Figure Description

🤝 Contributing and Testing New Models

We welcome contributions! Before you start, please:

  1. Check Existing Issues: Look for existing issues or discussions that may cover your idea.
  2. Fork and Clone: Fork the repository and clone it to your local machine.
  3. Create a Branch: Work on a new branch to keep your changes organized.
  4. Develop and Test: Develop your model and validate it using our provided testing script.
  5. Submit a Pull Request: Once ready, submit a PR with a clear description of your changes.

For detailed guidelines on how to structure your contributions, see below.ng instructions provided below.

Steps for Contributing

  1. Fork the Repository:

    • Fork the repository to your GitHub account.
    • Clone the forked repository to your local machine.
    git clone https://github.com/your-username/your-repository.git
    cd your-repository
  2. Create a New Branch:

    • Ensure you are on the develop branch and create a new branch for your model development.
    git checkout develop
    git checkout -b new-model-branch
  3. Develop Your Model:

    • Navigate to the mypackage/models/ directory.
    • Create your model class file, ensuring it follows the expected structure and naming conventions.
    • Implement the required methods (get_info, fit, predict) and attributes (topic_dict). Optionally, implement beta, theta, or corresponding methods (get_beta, get_theta).

Example Model Structure

Here is an example of how your model class should be structured:

importnumpyasnpfrommypackage.models.abstract_helper_models.baseimportBaseModel, TrainingStatusclassExampleModel(BaseModel):
def__init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._status=TrainingStatus.NOT_STARTEDdefget_info(self):
return {"model_name": "ExampleModel", "trained": False}
defany_other_processing_functions(self):
passdeffit(self, dataset, n_topics=3):
# do what you do during fitting the modelsself._status=TrainingStatus.INITIALIZEDself._status=TrainingStatus.RUNNINGself._status=TrainingStatus.SUCCEEDEDdefpredict(self, texts):
return [0] *len(texts)
# If self.beta or self.theta are not assigned during fitting, plese include these two methodsdefget_beta(self):
returnself.betadefget_theta(self):
returnself.theta

Testing Your Model

  1. Install Dependencies:

    • Ensure all dependencies are installed.
    pip install -r requirements.txt
  2. Validate Your Model:

    • To validate your model, use tests/validate_new_model.py to include your new model class.
    fromtests.model_validationimportvalidate_modelvalidate_model(NewModel)

If this validation fails, it will tell you

Validation Criteria

The following checks are performed during validation:

  • Presence of required methods (get_info, fit, predict).
  • Presence of required attributes (topic_dict).
  • Either presence of optional attributes (beta, theta) or corresponding methods (get_beta, get_theta).
  • Correct shape and sum of theta.
  • Proper status transitions during model fitting.
  • get_info method returns a dictionary with model_name and trained keys.

Refer to the tests/model_validation.py script for detailed validation logic.

Submitting Your Contribution

  1. Commit Your Changes:

    • Commit your changes to your branch.
    git add .
    git commit -m "Add new model: YourModelName"
  2. Push to GitHub:

    • Push your branch to your GitHub repository.
    git push origin new-model-branch
  3. Create a Pull Request:

    • Go to the original repository on GitHub.
    • Create a pull request from your forked repository and branch.
    • Provide a clear description of your changes and request a review.

We appreciate your contributions and strive to make the integration process as smooth as possible. If you encounter any issues or have questions, feel free to open an issue on GitHub. Happy coding!

If you want to include a new model where these guidelines are not approriate please mark this in your review request.

📜 Citation

If you use this project in your research, please consider citing:

STREAM

@inproceedings{thielmann-etal-2024-stream,
title = {STREAM: Simplified Topic Retrieval, Exploration, and Analysis Module},
author = {Thielmann, Anton and Reuter, Arik and Weisser, Christoph and Kant, Gillian and Kumar, Manish and S{\"a}fken, Benjamin},
booktitle = {Proceedings of the 62nd Annual Meeting of the Association for Computational Linguistics (Volume 2: Short Papers)},
year = {2024},
publisher = {Association for Computational Linguistics},
pages = {435--444},
}

Metrics and CEDC

@article{thielmann2024topics,
title={Topics in the haystack: Enhancing topic quality through corpus expansion},
author={Thielmann, Anton and Reuter, Arik and Seifert, Quentin and Bergherr, Elisabeth and S{\"a}fken, Benjamin},
journal={Computational Linguistics},
pages={1--37},
year={2024},
publisher={MIT Press One Broadway, 12th Floor, Cambridge, Massachusetts 02142, USA~…}
}

TNTM

@article{reuter2024probabilistic,
title={Probabilistic Topic Modelling with Transformer Representations},
author={Reuter, Arik and Thielmann, Anton and Weisser, Christoph and S{\"a}fken, Benjamin and Kneib, Thomas},
journal={arXiv preprint arXiv:2403.03737},
year={2024}
}

DCTE

@inproceedings{thielmann2024human,
title={Human in the Loop: How to Effectively Create Coherent Topics by Manually Labeling Only a Few Documents per Class},
author={Thielmann, Anton F and Weisser, Christoph and S{\"a}fken, Benjamin},
booktitle={Proceedings of the 2024 Joint International Conference on Computational Linguistics, Language Resources and Evaluation (LREC-COLING 2024)},
pages={8395--8405},
year={2024}
}

CBC

@inproceedings{thielmann2023coherence,
title={Coherence based document clustering},
author={Thielmann, Anton and Weisser, Christoph and Kneib, Thomas and S{\"a}fken, Benjamin},
booktitle={2023 IEEE 17th International Conference on Semantic Computing (ICSC)},
pages={9--16},
year={2023},
organization={IEEE}

If you use one of the Reddit or GME datasets, consider citing:

@article{kant2024one,
title={One-way ticket to the moon? An NLP-based insight on the phenomenon of small-scale neo-broker trading},
author={Kant, Gillian and Zhelyazkov, Ivan and Thielmann, Anton and Weisser, Christoph and Schlee, Michael and Ehrling, Christoph and S{\"a}fken, Benjamin and Kneib, Thomas},
journal={Social Network Analysis and Mining},
volume={14},
number={1},
pages={121},
year={2024},
publisher={Springer}
}

📝 License

STREAM is released under the MIT License. © 2024

About

ACL Python package engineered for seamless topic modeling, topic evaluation, and topic visualization. Ideal for text analysis, natural language processing (NLP), and research in the social sciences, STREAM simplifies the extraction, interpretation, and visualization of topics from large, complex datasets.

Topics

Resources

Code of conduct

Contributing

Stars

43 stars

Watchers

5 watching

Forks

Releases

Packages

Used by

Contributors

Languages