{"id":22388357,"url":"https://github.com/google-marketing-solutions/ml_toast","last_synced_at":"2025-07-31T06:32:44.233Z","repository":{"id":65981375,"uuid":"585418722","full_name":"google-marketing-solutions/ml_toast","owner":"google-marketing-solutions","description":"Cluster multilingual search terms captured from different time windows into semantically relevant topics.","archived":false,"fork":false,"pushed_at":"2024-07-30T21:17:40.000Z","size":157,"stargazers_count":35,"open_issues_count":3,"forks_count":7,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-06T21:23:54.596Z","etag":null,"topics":["data-science","machine-learning","marketing-science","nlp","tensorflow","topic-clustering"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/google-marketing-solutions.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-05T05:47:02.000Z","updated_at":"2025-03-05T05:11:34.000Z","dependencies_parsed_at":"2024-05-03T22:27:38.911Z","dependency_job_id":"f9ef071c-17f2-4a35-a0f4-1d32f8127ed2","html_url":"https://github.com/google-marketing-solutions/ml_toast","commit_stats":null,"previous_names":["google-marketing-solutions/ml_toast"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/google-marketing-solutions/ml_toast","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/google-marketing-solutions%2Fml_toast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/google-marketing-solutions%2Fml_toast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/google-marketing-solutions%2Fml_toast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/google-marketing-solutions%2Fml_toast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/google-marketing-solutions","download_url":"https://codeload.github.com/google-marketing-solutions/ml_toast/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/google-marketing-solutions%2Fml_toast/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267998182,"owners_count":24178477,"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","status":"online","status_checked_at":"2025-07-31T02:00:08.723Z","response_time":66,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["data-science","machine-learning","marketing-science","nlp","tensorflow","topic-clustering"],"created_at":"2024-12-05T02:13:14.689Z","updated_at":"2025-07-31T06:32:43.931Z","avatar_url":"https://github.com/google-marketing-solutions.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg align=\"left\" width=\"150\" src=\"https://services.google.com/fh/files/misc/ml_toast_logo.png\" alt=\"ml_toast_logo\"\u003e\u003c/img\u003e\u003cbr\u003e\n\n# 🍞 ML-ToAST: \u003cb\u003eM\u003c/b\u003eulti\u003cb\u003el\u003c/b\u003eingual \u003cb\u003eTo\u003c/b\u003epic Clustering of \u003cb\u003eA\u003c/b\u003eds-triggering \u003cb\u003eS\u003c/b\u003eearch \u003cb\u003eT\u003c/b\u003eerms\u003cbr\u003e\u003cbr\u003e\n\n**Disclaimer: This is not an official Google product.**\n\n[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/google/ml_toast/blob/main/ml_toast.ipynb)\n\n[What it solves](#challenges) •\n[How it works](#solution-overview) •\n[Get started](#get-started) •\n[References](#references)\n\n## Overview\n\n**🍞 ML-ToAST** is a tool that helps users cluster multilingual search terms\ncaptured from different time windows into semantically relevant topics. It\nhelps advertisers / marketers surface the topics or *themes* their audience are\ninterested in, and accordingly tailor their marketing activities.\n\nUnder the hood, the tool relies on Google's\n[Universal Sentence Encoder Multilingual](https://tfhub.dev/google/universal-sentence-encoder-multilingual/3)\nmodel to generate word embeddings, applies a couple of widely-used clustering\nalgorithms - namely\n[K-Means](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/compat/v1/estimator/experimental/KMeans)\nand [HDBSCAN](https://hdbscan.readthedocs.io/en/latest/) (with\n[UMAP](https://umap-learn.readthedocs.io/en/latest/) dimensionality reduction) -\nto generate clusters, and then selects the most meaningful term(s) to represent\neach cluster. Input / Output is supported via Google Sheets and Google Cloud\nBigQuery.\n\nThough the samples provided here are specific to Google Ads, the same approach\ncan quite seamlessly be used for any other advertising platform, or simply for\nany application where clustering of short texts is the goal.\n\n## Challenges\n\nAdvertisers spend a significant amount of time analyzing how customers are\nsearching for and engaging with their business, in order to understand:\n\n* Where their existing offerings resonate most; and\n* How they can tailor facets of their ads, such as landing pages and\n    creatives, to match changing consumer interest.\n\nOne of the approaches advertisers rely on is analyzing search queries against\nwhich their ads appear, categorizing these queries into meaningful themes, and\nanalyzing themes to generate insights.\n\n\u003e ***Topic clustering requires both time and expertise to execute properly, and\n\u003e may be computationally resource intensive.***\n\nIn the context of Google Ads, the\n[Search Terms report](https://support.google.com/google-ads/answer/2472708) for\na particular account lists all the search queries that have triggered the ads\ndefined in that account, along with performance metrics (such as clicks,\nimpressions, etc.). It is important to note that certain search terms that don't\nhave enough query activity are omitted from the report in order to maintain\nGoogle's standards on data privacy.\n\n\u003e ***Google Ads: though the\n\u003e [Search Terms report](https://support.google.com/google-ads/answer/2472708)\n\u003e can be downloaded and analyzed, it is cumbersome for advertisers to sift\n\u003e through thousands of queries - usually in multiple languages - to extract\n\u003e meaningful insights.***\n\nGoogle Ads employs several different\n[AI-powered search](https://services.google.com/fh/files/misc/unlock_the_power_of_search_2022.pdf)\noptimization features, one of which is Broad Match. Whereas other keyword\nmatching types focus only on syntax,\n[Broad Match](https://support.google.com/google-ads/answer/12159290) applies\nmatching based on semantics - the meaning conveyed by a search - in addition to\nsyntax. BM also looks at additional signals in the account - which include\nlanding pages, keywords in ad groups, previous searches, and more - in order to\nmatch more relevant traffic.\n\n\u003e ***Google Ads: the need to understand changing user interest is becoming ever\n\u003e more important, particularly with automated search optimization (e.g.\n\u003e [Broad Match](https://support.google.com/google-ads/answer/12159290)) becoming\n\u003e more fundamental.***\n\nGoogle Ads also provides\n[search term insights](https://support.google.com/google-ads/answer/11386930)\nwithin its user interface (UI). Search terms that triggered ads over the past 56\ndays are automatically analyzed and grouped into categories and subcategories,\nincluding performance metrics.\n\n\u003e ***Google Ads:\n\u003e [search term insights](https://support.google.com/google-ads/answer/11386930) -\n\u003e though technologically more sophisticated than the methodology applied here -\n\u003e cover the past 8 weeks only, are not available beyond the UI, and cannot be\n\u003e collated across accounts.***\n\n## Solution Overview\n\n🍞 ML-ToAST tackles the challenges mentioned above in a simple, configurable and\nprivacy-friendly way. Input is supported via a Google Sheets spreadsheet or\nGoogle Cloud BigQuery table. For spreadsheet-based input, search terms from\ndifferent lookback windows can be compared (configurable) to uncover terms that\nare *new / trending*, or also those that have not received enough impressions\n(configurable - unset by default). For BigQuery, the input is used as-is,\ntherefore any filtering or lookback comparison needs to be done in BigQuery\ndirectly. This input data represents the corpus of search terms that can be\nfurther analyzed and categorized into semantically relevant topics.\n\nAdditional input groups pertaining to Google Ads Broad Match (BM) are extracted\nand analyzed to:\n\n* Provide more transparency into BM's performance; and\n* Give advertisers more control via keyword recommendations that they could\n  add to / exclude from BM.\n\nThe figure below provides an overview of the core functionality of the tool.\n\n\u003ccenter\u003e\n  \u003cimg\n    src=\"https://services.google.com/fh/files/misc/ml_toast_diagram.png\"\n    alt=\"ml_toast_diagram\"\n  /\u003e\n\u003c/center\u003e\n\n### Get Started\n\nThe quickest way to get started with 🍞 ML-ToAST is to load the `ml_toast.ipynb`\nnotebook in Google Colaboratory via the link below:\n\n[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/google/ml_toast/blob/main/ml_toast.ipynb)\n\nThe notebook provides an easy to use interface for configuring and running the\ntool, along with a code walkthrough and results visualization.\n\nAlternatively, you can build the tool using the provided `requirements.txt`:\n\n```shell\npip install -r requirements.txt\n```\n\nand run `topic_clustering.py` manually, passing in the desired arguments:\n\n  Usage:\n\n  ```shell\n  topic_clustering.py   --csv_data_path=\u003cINPUT_DATA_PATH\u003e\n                        --output_path=\u003cOUTPUT_DATA_PATH\u003e\n                        [--data_id=\u003cINPUT_DATA_ID\u003e]\n                        [--input_col=\u003cINPUT_DATA_COLUMN\u003e]\n                        [--output_kmeans_col=\u003cOUTPUT_KMEANS_COL\u003e]\n                        [--output_hdbscan_col=\u003cOUTPUT_HDBSCAN_COLUMN\u003e]\n                        [--stop_words=\u003cSTOP_WORDS\u003e]\n                        [--kmeans_clusters=\u003cKMEANS_CLUSTERS\u003e]\n                        [--umap_n_neighbors=\u003cUMAP_N_NEIGHBORS\u003e]\n                        [--umap_n_components=\u003cUMAP_N_COMPONENTS\u003e]\n                        [--umap_random_state=\u003cUMAP_RANDOM_STATE\u003e]\n                        [--hdbscan_min_cluster_size=\u003cHDBSCAN_MIN_CLUSTER_SIZE\u003e]\n                        [--hdbscan_min_samples=\u003cHDBSCAN_MIN_SAMPLES\u003e]\n                        [--opt_threshold_unclustered=\u003cOPT_THRESHOLD_UNCLUSTERED\u003e]\n                        [--opt_threshold_recluster=\u003cOPT_THRESHOLD_RECLUSTER\u003e]\n                        [--hyperparameter_tuning] [--nohyperparameter_tuning]\n  ```\n\n  Options:\n\n  ```console\n  --help                show this help message\n  --csv_data_path=\u003cINPUT_DATA_PATH\u003e\n                        path to a csv file containing the data to use. Defaults\n                        to the path 'samples/data.csv' relative to the current\n                        (root) directory.\n  --output_path=\u003cOUTPUT_DATA_PATH\u003e\n                        path where the output should be stored. Defaults to the\n                        path 'output/data.csv' relative to the current (root)\n                        directory.\n  --data_id=\u003cINPUT_DATA_ID\u003e\n                        identifier of the input data. Useful for logging when\n                        running the module with different inputs. Defaults to\n                        the value 'data'.\n  --input_col=\u003cINPUT_DATA_COL\u003e\n                        column in the input data corresponding to the\n                        documents to cluster. Defaults to the value 'document'.\n  --output_kmeans_col=\u003cOUTPUT_KMEANS_COLUMN\u003e\n                        column to write the generated K-Means cluster\n                        assignments to. Defaults to the value 'topics_kmeans'.\n  --output_hdbscan_col=\u003cOUTPUT_HDBSCAN_COLUMN\u003e\n                        column to write the generated HDBSCAN cluster\n                        assignments to. Defaults to the value 'topics_hdbscan'.\n  --stop_words=\u003cSTOP_WORDS\u003e\n                        list of custom words to use as stop words for the\n                        generated topic labels. Defaults to None.\n  --kmeans_clusters=\u003cKMEANS_CLUSTERS\u003e\n                        list of clusters to use to identify the optimal value of\n                        K. Defaults to the range 5-15.\n  --umap_n_neighbors=\u003cUMAP_N_NEIGHBORS\u003e\n                        hyperparameter 'n_neighbors' for UMAP. Defaults to 15.\n                        See https://umap-learn.readthedocs.io/en/latest/parameters.html#n-neighbors\n                        for more information.\n  --umap_n_components=\u003cUMAP_N_COMPONENTS\u003e\n                        hyperparameter 'n_components' for UMAP. Defaults to 30.\n                        See https://umap-learn.readthedocs.io/en/latest/parameters.html#n_components\n                        for more information.\n  --umap_random_state=\u003cUMAP_RANDOM_STATE\u003e\n                        random seed for UMAP. Defaults to None.\n                        Consider setting an explicit value (e.g. 32) for\n                        reproducability. See https://umap-learn.readthedocs.io/en/latest/reproducibility.html\n                        for more information.\n  --hdbscan_min_cluster_size=\u003cHDBSCAN_MIN_CLUSTER_SIZE\u003e\n                        hyperparameter 'min_cluster_size' for HDBSCAN. Defaults\n                        to 20. See\n                        https://hdbscan.readthedocs.io/en/latest/parameter_selection.html#selecting-min-cluster-size\n                        for more information.\n  --hdbscan_min_samples=\u003cHDBSCAN_MIN_SAMPLES\u003e\n                        hyperparameter 'min_samples' for HDBSCAN. Defaults to 5.\n                        See https://hdbscan.readthedocs.io/en/latest/parameter_selection.html#selecting-min-samples\n                        for more information.\n  --opt_threshold_unclustered=\u003cOPT_THRESHOLD_UNCLUSTERED\u003e\n                        1 of 2 thresholds for optimizing generated HDBSCAN\n                        clusters through linear regression. This represents the\n                        threshold for clustering unassigned data points (HDBSCAN\n                        label = -1). Defaults to assign data points with at\n                        least 40% (0.4) predicted cluster assignment confidence.\n  --opt_threshold_recluster=\u003cOPT_THRESHOLD_RECLUSTER\u003e\n                        1 of 2 thresholds for optimizing generated HDBSCAN\n                        clusters through linear regression. This represents the\n                        threshold for reclustering assigned data points (HDBSCAN\n                        label != -1). Defaults to reassign data points with at\n                        least 80% (0.8) predicted cluster assignment confidence\n                        from their original HDBSCAN cluster to their predicted\n                        cluster.\n  --hyperparameter_tuning --nohyperparameter_tuning\n                        whether to perform bayesian optimization to find the\n                        optimal hyperparameters for UMAP + HDBSCAN or not.\n                        Defaults to True.\n  ```\n\n\u003e Please note that the tool relies on the `tensorflow-text` package, which is\n\u003e no longer available for all platforms (e.g. Apple Macs and Windows) and\n\u003e accordingly might need to be built from source. Refer to these\n\u003e [instructions](https://github.com/tensorflow/text#a-note-about-different-operating-system-packages)\n\u003e for more information.\n\n## Citing ML-ToAST\n\nTo cite this repository:\n\n```\n@software{ml_toast_github,\n  author = {Mohab Fekry and Christiane Ahlheim and Victor Paunescu},\n  title = {ML-ToAST: Multilingual Topic Clustering of Ads-triggering Search Terms},\n  url = {https://github.com/google/ml_toast},\n  version = {0.1.0},\n  year = {2023},\n}\n```\n\n## References\n\n- [Kong, J., Scott, A., \u0026 Goerg, G. M. (2016). Improving topic clustering on search queries with word co-occurrence and bipartite graph co-clustering. Google Research.](https://research.google/pubs/pub45569/)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoogle-marketing-solutions%2Fml_toast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgoogle-marketing-solutions%2Fml_toast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgoogle-marketing-solutions%2Fml_toast/lists"}