Skip to main content

Divisi - Interactive Subgroup Discovery

Divisi is a tool to find interpretable patterns in large datasets that can be expressed as tabular features (for example, transactions, survey responses, electronic health records, or text documents). It runs faster than existing rule-based subgroup discovery algorithms and has an interactive interface to help you probe and curate subgroups of interest. Check out the paper (CHI 2025) to learn more.

Quickstart

Optionally create a virtual environment with Python >3.7. Install the package:

pip install divisi-toolkit

Install Jupyter Notebook or Jupyter Lab if not already installed. Then start a Jupyter server. The example_data/demo.ipynb notebook shows how to start the interactive widget or use the subgroup discovery algorithm programmatically.

Usage

To run Divisi, you first need to create a preprocessed, discretized version of your dataset. The easiest way is to take a Pandas dataframe and run the discretize_data command:

import divisi

discrete_df = divisi.discretize_data(
    df, 
    custom_cols={
        # Specify custom discretization strategies here
        'Age': divisi.bin_values(quantiles=5),
        # ...
    }, 
    remove_cols=[
        # Specify columns to remove from subgroup discovery
        'Label'
        # ...
    ])

If you have a text dataset, you can also use the discretize_token_sets method. (TODO provide example of text encoding)

Then, to use the Divisi interface in a notebook, simply create a DivisiWidget instance:

w = divisi.DivisiWidget(
    discrete_df, 
    # provide a path to store interface state so you can pick up where you left off
    state_path="divisi_state",
    # metrics to display for each subgroup (must be numpy arrays)
    metrics={
        "Label": y,
        "Error": is_error
    })
w

By default, ranking functions will be created based on the metrics you provide. You can also provide ranking functions using the ranking_functions keyword argument to the DivisiWidget constructor. The following ranking functions are available in divisi.ranking:

  • OutcomeRate(y: ndarray, inverse: bool = false): Prioritizes subgroups with a higher rate of the given binary outcome y within the subgroup. If inverse is True, prioritizes subgroups with a lower rate.
  • OutcomeShare(y: ndarray): Prioritizes subgroups that capture more of the positive instances of the binary outcome y. Helps to measure coverage of the subgroup.
  • InteractionEffect(y: ndarray): Prioritizes subgroups for which all rule features contribute highly to the rate of the given binary outcome.
  • MeanDifference(y: ndarray): Prioritizes subgroups which have a mean of the given continuous metric y substantially different from the average.
  • Entropy(y: ndarray, inverse: bool = false): Prioritizes subgroups with a lower (or, if inverse is True, higher) entropy for the given integer-valued metric y inside the subgroup than outside.
  • SubgroupSize(ideal_fraction: number, spread: number): Scores subgroups by their size according to a Gaussian curve with a mean of ideal_fraction and a standard deviation of spread.
  • SimpleRule(): Prioritizes subgroups defined by rules with fewer features.

Programmatic Usage

To generate subgroups using pure Python without the interface, initialize an instance of SamplingSubgroupSearch with the discretized data object, ranking functions, and any search parameters, then run the sampler:

finder = divisi.sampling.SamplingSubgroupSearch(
    discrete_df,
    {
        "High True Labels": divisi.ranking.OutcomeRate(y),
        "High Errors": divisi.ranking.OutcomeRate(is_error),
        "Simple Rule": divisi.ranking.SimpleRule()
    },
    # additional sampling options
    min_items_fraction=0.05
    # ...
)

results, _ = finder.sample(50)

After running the sampler, you can re-rank the results based on the provided ranking functions without rerunning the search:

for rule in results.rank({"High True Labels": 1.0, "Simple Rule": 0.25}):
    # rule.feature gets the predicate, rule.score_values contains the scores for each ranking function
    print(rule)
    # make a boolean mask over the dataframe corresponding to the rule
    mask = discrete_df.mask_for_rule(rule)

Citation

Please use the following citation if using Divisi in your projects:

@inproceedings{sivaraman2025divisi,
	title = {{Divisi: Interactive Search and Visualization for Scalable Exploratory Subgroup Analysis}},
	author = {Sivaraman, Venkatesh and Li, Zexuan and Perer, Adam},
	year = {2025},
    publisher = {Association for Computing Machinery},
    address = {New York, NY, USA},
    doi = {10.1145/3706598.3713103},
    booktitle = {Proceedings of the CHI Conference on Human Factors in Computing Systems},
    numpages = {17},
    location = {Yokohama, Japan},
    series = {CHI '25}
}

If you have a cool use case for Divisi, tell us about it!

Running in Development Mode

To develop the frontend, make sure you have an up-to-date version of NodeJS in your terminal, then run:

cd client
npm install
vite

The vite command starts a live hot-reload server for the frontend. Then, when you initialize the DivisiWidget, pass the dev=True keyword argument to use the live server. (Make sure that you don't have anything else running on port 5173 while you do this.)

Metadata

Release files for divisi-toolkit 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for divisi-toolkit 0.3.0
File Size Uploaded Provenance Actions
divisi_toolkit-0.3.0.tar.gz 451.5 kB Without provenance Details for divisi_toolkit-0.3.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for divisi-toolkit 0.3.0
File Interpreter ABI Platform Actions
divisi_toolkit-0.3.0-py3-none-any.whl Python 3 none any Details for divisi_toolkit-0.3.0-py3-none-any.whl

Total release size: 706.6 kB

Release files / divisi_toolkit-0.3.0.tar.gz

Download URL divisi_toolkit-0.3.0.tar.gz
Size 451.5 kB
Tags Source
SHA-256 checksum
How to use checksums
03de8267d16e5bdedea7778cd51ce9b2e55f2faa9acf3ac0493ad770bbd0ca78
BLAKE2b-256 checksum
How to use checksums
ac104250a2bfc92ec23d17aff15dd695b9e698b2b706842e7b6fbeea58990f71
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.11.5

Release files / divisi_toolkit-0.3.0-py3-none-any.whl

Download URL divisi_toolkit-0.3.0-py3-none-any.whl
Size 255.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
19fad53dcf6ceadf7e7b37f5f1c1147dd3c63516d58a830182a9553b2e5e4f83
BLAKE2b-256 checksum
How to use checksums
f4c633db82984cec041e472e8bc64f4b46775ca2859d71a2dee51eedf0833dcc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.11.5

Security for divisi-toolkit 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page