{"id":24513605,"url":"https://github.com/andrewtavis/kwx","last_synced_at":"2025-04-14T08:50:31.967Z","repository":{"id":44340620,"uuid":"323951427","full_name":"andrewtavis/kwx","owner":"andrewtavis","description":"BERT, LDA, and TFIDF based keyword extraction in Python","archived":false,"fork":false,"pushed_at":"2024-03-20T15:49:36.000Z","size":12902,"stargazers_count":72,"open_issues_count":14,"forks_count":10,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-03-27T22:22:12.289Z","etag":null,"topics":["bert","data-analysis","data-science","data-visualization","keyword-extraction","latent-dirichlet-allocation","lda","machine-learning","multilingual","natural-language-processing","nlp","open-source","python","python3","text-analysis","text-classification","text-mining","tfidf","topic-modeling","unsupervised-learning"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andrewtavis.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-12-23T16:31:53.000Z","updated_at":"2025-03-22T09:00:04.000Z","dependencies_parsed_at":"2023-11-24T20:43:15.243Z","dependency_job_id":null,"html_url":"https://github.com/andrewtavis/kwx","commit_stats":{"total_commits":221,"total_committers":4,"mean_commits":55.25,"dds":"0.018099547511312264","last_synced_commit":"ca984e34eae642c026389a75a5b42cfdd248fcc3"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewtavis%2Fkwx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewtavis%2Fkwx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewtavis%2Fkwx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrewtavis%2Fkwx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrewtavis","download_url":"https://codeload.github.com/andrewtavis/kwx/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248852079,"owners_count":21171837,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bert","data-analysis","data-science","data-visualization","keyword-extraction","latent-dirichlet-allocation","lda","machine-learning","multilingual","natural-language-processing","nlp","open-source","python","python3","text-analysis","text-classification","text-mining","tfidf","topic-modeling","unsupervised-learning"],"created_at":"2025-01-22T00:55:41.975Z","updated_at":"2025-04-14T08:50:31.946Z","avatar_url":"https://github.com/andrewtavis.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://github.com/andrewtavis/kwx\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/andrewtavis/kwx/main/.github/resources/logo/kwx_logo_transparent.png\" width=431 height=215\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n\u003col\u003e\u003c/ol\u003e\n\n[![rtd](https://img.shields.io/readthedocs/kwx.svg?logo=read-the-docs)](http://kwx.readthedocs.io/en/latest/)\n[![ci](https://img.shields.io/github/actions/workflow/status/andrewtavis/kwx/.github/workflows/ci.yml?branch=main?logo=github)](https://github.com/andrewtavis/kwx/actions?query=workflow%3ACI)\n[![codecov](https://codecov.io/gh/andrewtavis/kwx/branch/main/graphs/badge.svg)](https://codecov.io/gh/andrewtavis/kwx)\n[![pyversions](https://img.shields.io/pypi/pyversions/kwx.svg?logo=python\u0026logoColor=FFD43B\u0026color=306998)](https://pypi.org/project/kwx/)\n[![pypi](https://img.shields.io/pypi/v/kwx.svg?color=4B8BBE)](https://pypi.org/project/kwx/)\n[![pypistatus](https://img.shields.io/pypi/status/kwx.svg)](https://pypi.org/project/kwx/)\n[![license](https://img.shields.io/github/license/andrewtavis/kwx.svg)](https://github.com/andrewtavis/kwx/blob/main/LICENSE.txt)\n[![coc](https://img.shields.io/badge/coc-Contributor%20Covenant-ff69b4.svg)](https://github.com/andrewtavis/kwx/blob/main/.github/CODE_OF_CONDUCT.md)\n[![codestyle](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)\n[![colab](https://img.shields.io/badge/%20-Open%20in%20Colab-097ABB.svg?logo=google-colab\u0026color=097ABB\u0026labelColor=525252)](https://colab.research.google.com/github/andrewtavis/kwx)\n\n## BERT, LDA, and TFIDF based keyword extraction in Python\n\n**kwx** is a toolkit for multilingual keyword extraction based on Google's [BERT](https://github.com/google-research/bert), [Latent Dirichlet Allocation](https://en.wikipedia.org/wiki/Latent_Dirichlet_allocation) and [Term Frequency Inverse Document Frequency](https://en.wikipedia.org/wiki/Tf%E2%80%93idf). The package provides a suite of methods to process texts of any language to varying degrees and then extract and analyze keywords from the created corpus (see [kwx.languages](https://github.com/andrewtavis/kwx/blob/main/src/kwx/languages.py) for the various degrees of language support). A unique focus is allowing users to decide which words to not include in outputs, thereby guaranteeing sensible results that are in line with user intuitions.\n\nFor a thorough overview of the process and techniques see the [Google slides](https://docs.google.com/presentation/d/1BNddaeipNQG1mUTjBYmrdpGC6xlBvAi3rapT88fkdBU/edit?usp=sharing), and reference the [documentation](https://kwx.readthedocs.io/en/latest/) for explanations of the models and visualization methods.\n\n\u003ca id=\"contents\"\u003e\u003c/a\u003e\n\n# **Contents**\n\n- [Installation](#installation)\n- [Models](#models)\n  - [BERT](#bert)\n  - [LDA](#lda)\n  - [TFIDF](#tfidf)\n  - [Word Frequency](#word-frequency)\n- [Usage](#usage)\n  - [Text Cleaning](#text-cleaning)\n  - [Keyword Extraction](#keyword-extraction)\n- [Visuals](#visuals)\n  - [Topic Number Evaluation](#topic-number-evaluation)\n  - [t-SNE](#t-sne)\n  - [pyLDAvis](#pyldavis)\n  - [Word Cloud](#word-cloud)\n- [To-Do](#to-do)\n\n\u003ca id=\"installation\"\u003e\u003c/a\u003e\n\n# Installation [`⇧`](#contents)\n\nkwx can be downloaded from PyPI via pip or sourced directly from this repository:\n\n```bash\npip install kwx\n```\n\n```bash\ngit clone https://github.com/andrewtavis/kwx.git\ncd kwx\npython setup.py install\n```\n\n```python\nimport kwx\n```\n\n\u003ca id=\"models\"\u003e\u003c/a\u003e\n\n# Models [`⇧`](#contents)\n\nImplemented NLP modeling methods within [kwx.model](https://github.com/andrewtavis/kwx/blob/main/src/kwx/model.py) include:\n\n\u003ca id=\"bert\"\u003e\u003c/a\u003e\n\n### • BERT [`⇧`](#contents)\n\n[Bidirectional Encoder Representations from Transformers](https://github.com/google-research/bert) derives representations of words based on nlp models ran over open-source Wikipedia data. These representations are then leveraged to derive corpus topics.\n\nkwx uses [sentence-transformers](https://github.com/UKPLab/sentence-transformers) pretrained models. See their GitHub and [documentation](https://www.sbert.net/) for the available models.\n\n\u003ca id=\"lda\"\u003e\u003c/a\u003e\n\n### • LDA [`⇧`](#contents)\n\n[Latent Dirichlet Allocation](https://en.wikipedia.org/wiki/Latent_Dirichlet_allocation) is a generative statistical model that allows sets of observations to be explained by unobserved groups that explain why some parts of the data are similar. In the case of kwx, documents or text entries are posited to be a mixture of a given number of topics, and the presence of each word in a text body comes from its relation to these derived topics.\n\nAlthough not as computationally robust as some machine learning models, LDA provides quick results that are suitable for many applications. Specifically for keyword extraction, in most settings the results are similar to those of BERT in a fraction of the time.\n\n\u003ca id=\"tfidf\"\u003e\u003c/a\u003e\n\n### • TFIDF [`⇧`](#contents)\n\nThe user can also compute [Term Frequency Inverse Document Frequency](https://en.wikipedia.org/wiki/Tf%E2%80%93idf) keywords - those that are unique in a text body in comparison to another that's compared. This is a useful baseline when a user has another text or text body to compare the target corpus against.\n\n\u003ca id=\"word-frequency\"\u003e\u003c/a\u003e\n\n### • Word Frequency [`⇧`](#contents)\n\nFinally a user can simply query the most common words from a text corpus. This method is used in kwx as a baseline to check model efficacy.\n\n\u003ca id=\"usage\"\u003e\u003c/a\u003e\n\n# Usage [`⇧`](#contents)\n\nKeyword extraction can be useful to analyze surveys, tweets and other kinds of social media posts, research papers, and further classes of texts. [examples/kw_extraction](https://github.com/andrewtavis/kwx/blob/main/examples/kw_extraction.ipynb) provides an example of how to use kwx by deriving keywords from tweets in the Kaggle [Twitter US Airline Sentiment](https://www.kaggle.com/crowdflower/twitter-airline-sentiment) dataset.\n\nThe following outlines using kwx to derive keywords from a text corpus with `prompt_remove_words` as `True` (the user will be asked if some of the extracted words need to be replaced):\n\n\u003ca id=\"text-cleaning\"\u003e\u003c/a\u003e\n\n### • Text Cleaning [`⇧`](#contents)\n\n```python\nfrom kwx.utils import prepare_data\n\ninput_language = \"english\" # see kwx.languages for options\n\n# kwx.utils.clean() can be used on a list of lists\ntext_corpus = prepare_data(\n    data=\"df_or_csv_xlsx_path\",\n    target_cols=\"cols_where_texts_are\",\n    input_language=input_language,\n    min_token_freq=0,  # for BERT\n    min_token_len=0,  # for BERT\n    remove_stopwords=False,  # for BERT\n    verbose=True,\n)\n```\n\n\u003ca id=\"keyword-extraction\"\u003e\u003c/a\u003e\n\n### • Keyword Extraction [`⇧`](#contents)\n\n```python\nfrom kwx.model import extract_kws\n\nnum_keywords = 15\nnum_topics = 10\nignore_words = [\"words\", \"user\", \"knows\", \"they\", \"don't\", \"want\"]\n\n# Remove n-grams for BERT training\ncorpus_no_ngrams = [\n    \" \".join([t for t in text.split(\" \") if \"_\" not in t]) for text in text_corpus\n]\n\n# We can pass keywords for sentence_transformers.SentenceTransformer.encode,\n# gensim.models.ldamulticore.LdaMulticore, or sklearn.feature_extraction.text.TfidfVectorizer\nbert_kws = extract_kws(\n    method=\"BERT\", # \"BERT\", \"LDA\", \"TFIDF\", \"frequency\"\n    bert_st_model=\"xlm-r-bert-base-nli-stsb-mean-tokens\",\n    text_corpus=corpus_no_ngrams,  # automatically tokenized if using LDA\n    input_language=input_language,\n    output_language=None,  # allows the output to be translated\n    num_keywords=num_keywords,\n    num_topics=num_topics,\n    corpuses_to_compare=None,  # for TFIDF\n    ignore_words=ignore_words,\n    prompt_remove_words=True,  # check words with user\n    show_progress_bar=True,\n    batch_size=32,\n)\n```\n\n```_output\nThe BERT keywords are:\n\n['time', 'flight', 'plane', 'southwestair', 'ticket', 'cancel', 'united', 'baggage',\n'love', 'virginamerica', 'service', 'customer', 'delay', 'late', 'hour']\n\nShould words be removed [y/n]? y\nType or copy word(s) to be removed: southwestair, united, virginamerica\n\nThe new BERT keywords are:\n\n['late', 'baggage', 'service', 'flight', 'time', 'love', 'book', 'customer',\n'response', 'hold', 'hour', 'cancel', 'cancelled_flighted', 'delay', 'plane']\n\nShould words be removed [y/n]? n\n```\n\nThe model will be rerun until all words known to be unreasonable are removed for a suitable output. [kwx.model.gen_files](https://github.com/andrewtavis/kwx/blob/main/src/kwx/model.py) could also be used as a run-all function that produces a directory with a keyword text file and visuals (for experienced users wanting quick results).\n\n\u003ca id=\"visuals\"\u003e\u003c/a\u003e\n\n# Visuals [`⇧`](#contents)\n\n[kwx.visuals](https://github.com/andrewtavis/kwx/blob/main/src/kwx/visuals.py) includes the following functions for presenting and analyzing the results of keyword extraction:\n\n\u003ca id=\"topic-number-evaluation\"\u003e\u003c/a\u003e\n\n### • Topic Number Evaluation [`⇧`](#contents)\n\nA graph of topic coherence and overlap given a variable number of topics to derive keywords from.\n\n```python\nfrom kwx.visuals import graph_topic_num_evals\nimport matplotlib.pyplot as plt\n\ngraph_topic_num_evals(\n    method=[\"lda\", \"bert\"],\n    text_corpus=text_corpus,\n    num_keywords=num_keywords,\n    topic_nums_to_compare=list(range(5, 15)),\n    metrics=True, #  stability and coherence\n)\nplt.show()\n```\n\n\u003cp align=\"middle\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/andrewtavis/kwx/main/.github/resources/images/topic_num_eval.png\" width=\"600\" /\u003e\n\u003c/p\u003e\n\n\u003ca id=\"t-sne\"\u003e\u003c/a\u003e\n\n### • t-SNE [`⇧`](#contents)\n\n[t-SNE](https://en.wikipedia.org/wiki/T-distributed_stochastic_neighbor_embedding) allows the user to visualize their topic distribution in both two and three dimensions. Currently available just for LDA, this technique provides another check for model suitability.\n\n```python\nfrom kwx.visuals import t_sne\nimport matplotlib.pyplot as plt\n\nt_sne(\n    dimension=\"both\",  # 2d and 3d are options\n    text_corpus=text_corpus,\n    num_topics=10,\n    remove_3d_outliers=True,\n)\nplt.show()\n```\n\n\u003cp align=\"middle\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/andrewtavis/kwx/main/.github/resources/images/t_sne.png\" width=\"600\" /\u003e\n\u003c/p\u003e\n\n\u003ca id=\"pyldavis\"\u003e\u003c/a\u003e\n\n### • pyLDAvis [`⇧`](#contents)\n\n[pyLDAvis](https://github.com/bmabey/pyLDAvis) is included so that users can inspect LDA extracted topics, and further so that it can easily be generated for output files.\n\n```python\nfrom kwx.visuals import pyLDAvis_topics\n\npyLDAvis_topics(\n    method=\"lda\",\n    text_corpus=text_corpus,\n    num_topics=10,\n    display_ipython=False,  # For Jupyter integration\n)\n```\n\n\u003cp align=\"middle\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/andrewtavis/kwx/main/.github/resources/images/pyLDAvis.png\" width=\"600\" /\u003e\n\u003c/p\u003e\n\n\u003ca id=\"word-cloud\"\u003e\u003c/a\u003e\n\n### • Word Cloud [`⇧`](#contents)\n\nWord clouds via [wordcloud](https://github.com/amueller/word_cloud) are included for a basic representation of the text corpus - specifically being a way to convey basic visual information to potential stakeholders. The following figure from [examples/kw_extraction](https://github.com/andrewtavis/kwx/blob/main/examples/kw_extraction.ipynb) shows a word cloud generated from tweets of US air carrier passengers:\n\n```python\nfrom kwx.visuals import gen_word_cloud\n\nignore_words = [\"words\", \"user\", \"knows\", \"they\", \"don't\", \"want\"]\n\ngen_word_cloud(\n    text_corpus=text_corpus,\n    ignore_words=None,\n    height=500,\n)\n```\n\n\u003cp align=\"middle\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/andrewtavis/kwx/main/.github/resources/images/word_cloud.png\" width=\"600\" /\u003e\n\u003c/p\u003e\n\n\u003ca id=\"to-do\"\u003e\u003c/a\u003e\n\n# To-Do [`⇧`](#contents)\n\nPlease see the [contribution guidelines](https://github.com/andrewtavis/kwx/blob/main/.github/CONTRIBUTING.md) if you are interested in contributing to this project. Work that is in progress or could be implemented includes:\n\n- Including more methods to extract keywords [(see issue)](https://github.com/andrewtavis/kwx/issues/17)\n\n- Adding key phrase extraction as an option for [kwx.model.extract_kws](https://github.com/andrewtavis/kwx/blob/main/src/kwx/model.py) [(see issues)](https://github.com/andrewtavis/kwx/issues/)\n\n- Adding t-SNE and pyLDAvis style visualizations for BERT models [(see issues\\)](https://github.com/andrewtavis/kwx/issues/45)\n\n- Converting the translation feature over to use another translation api rather than [py-googletrans](https://github.com/ssut/py-googletrans) [(see issue)](https://github.com/andrewtavis/kwx/issues/44)\n\n- Updates to [kwx.languages](https://github.com/andrewtavis/kwx/blob/main/src/kwx/languages.py) as lemmatization and other linguistic package dependencies evolve\n\n- Creating, improving and sharing [examples](https://github.com/andrewtavis/kwx/tree/main/examples)\n\n- Improving [tests](https://github.com/andrewtavis/kwx/tree/main/tests) for greater [code coverage](https://codecov.io/gh/andrewtavis/kwx)\n\n- Updating and refining the [documentation](https://kwx.readthedocs.io/en/latest/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrewtavis%2Fkwx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrewtavis%2Fkwx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrewtavis%2Fkwx/lists"}