DivExplorer


NameDivExplorer JSON
Version 0.2.1 PyPI version JSON
download
home_page
SummaryAnalyze Pandas dataframes, and other tabular data (csv), to find subgroups of data with properties that diverge from those of the overall dataset
upload_time2023-11-10 19:37:45
maintainer
docs_urlNone
author
requires_python>=3.7
licenseMIT License Copyright (c) 2021-23 Eliana Pastor Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords pandas fairness subgroup analysis data mining
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/divexplorer/divexplorer/main.svg)](https://results.pre-commit.ci/latest/github/divexplorer/divexplorer/main)
[![PyPI](https://img.shields.io/pypi/v/divexplorer)](https://pypi.org/project/divexplorer/)
[![Downloads](https://pepy.tech/badge/divexplorer)](https://pepy.tech/project/divexplorer)

# DivExplorer

- [DivExplorer](#divexplorer)
  - [Installation](#installation)
  - [Usage](#usage)
    - [Notebooks](#notebooks)
    - [Package](#package)
  - [Paper](#paper)
  - [Contributing](#contributing)

Machine learning models may perform differently on different data subgroups. We propose the notion of divergence over itemsets (i.e., conjunctions of simple predicates) as a measure of different classification behavior on data subgroups, and the use of frequent pattern mining techniques for their identification. We quantify the contribution of different attribute values to divergence with the notion of Shapley values to identify both critical and peculiar behaviors of attributes.
See our [paper](https://divexplorer.github.io/static/DivExplorer.pdf) and our [project page](https://divexplorer.github.io/) for all the details.

## Installation

Install using [pip](http://www.pip-installer.org/en/latest) with:

<pre>
pip install divexplorer
</pre>

or, download a wheel or source archive from [PyPI](https://pypi.org/project/divexplorer/).

## Example Notebooks

This [notebook](https://github.com/divexplorer/divexplorer/blob/main/notebooks/DivExplorerExample.ipynb) gives an example of how to use DivExplorer to find divergent subgroups in datasets and in the predictions of a classifier.
You can also [run the notebook directly on Colab](https://colab.research.google.com/drive/1lDqqssBusiFHjgR6EciuWNT55hO4_X0o?usp=sharing). 

## Quick Start

DivExplorer works on Pandas datasets.  Here we load an example one, and discretize in coarser ranges one of its attributes. 

```python
import pandas as pd

df_census = pd.read_csv('https://raw.githubusercontent.com/divexplorer/divexplorer/main/datasets/census_income.csv')
df_census["AGE_RANGE"] = df_census.apply(lambda row : 10 * (row["A_AGE"] // 10), axis=1)
```

We can then find the data subgroups that have highest income divergence, using the `DivergenceExplorer` class as follows: 

```python
from divexplorer import DivergenceExplorer

fp_diver = DivergenceExplorer(df_census)
subgroups = fp_diver.get_pattern_divergence(min_support=0.001, quantitative_outcomes=["PTOTVAL"])
subgroups.sort_values(by="PTOTVAL_div", ascending=False).head(10)
```

### Finding subgroups with divergent performance in classifiers

For classifiers, it may be of interest to find the subgroups with the highest (or lowest) divergence in characteristics such as false positive rates, etc.  Here is how to do it for the false-positive rate in a COMPAS-derived classifier. 

```python
compas_df = pd.read_csv('https://raw.githubusercontent.com/divexplorer/divexplorer/main/datasets/compas_discretized.csv')
```

We generate an `fp` column whose average will give the false-positive rate, like so: 

```python
from divexplorer.outcomes import get_false_positive_rate_outcome

y_trues = compas_df["class"]
y_preds = compas_df["predicted"]

compas_df['fp'] =  get_false_positive_rate_outcome(y_trues, y_preds)
```

The `fp` column has values: 

* 1, if the data is a false positive (`class` is 0 and `predicted` is 1)
* 0, if the data is a true negative (`class` is 0 and `predicted` is 0). 
* NaN, if the class is positive (`class` is 1).

We use Nan for `class` 1 data, to exclude those data from the average, so that the column average is the false-positive rate.
We can then find the most divergent groups as in the previous example, noting that here we use `boolean_outcomes` rather than `quantitative_outcomes` because `fp` is boolean: 

```python
fp_diver = DivergenceExplorer(compas_df)

attributes = ['race', '#prior', 'sex', 'age']
FP_fm = fp_diver.get_pattern_divergence(min_support=0.1, attributes=attributes, 
                                        boolean_outcomes=['fp'])
FP_fm.sort_values(by="fp_div", ascending=False).head(10)
```

Note how we specify the attributes that can be used to define subgroups. 

### Analyzing subgroups via Shapley values

If we want to analyze what factors contribute to the divergence of a particular subgroup, we can do so via Shapley values: 

```python
fp_details = DivergencePatternProcessor(FP_fm, 'fp')

pattern = fp_details.patterns['itemset'].iloc[37]
fp_details.shapley_value(pattern)
```

### Pruning redundant subgroups

If you get too many subgroups, you can prune redundant ones via _redundancy pruning_. 
This prunes a pattern $\beta$ if there is a pattern $\alpha$, subset of $\beta$, with a divergence difference below a threshold. 

```python
df_pruned = fp_details.redundancy_pruning(th_redundancy=0.01)
df_pruned.sort_values("fp_div", ascending=False).head(5)
```

## Papers

The original paper is:

> [Looking for Trouble: Analyzing Classifier Behavior via Pattern Divergence](https://divexplorer.github.io/static/DivExplorer.pdf). [Eliana Pastor](https://github.com/elianap), [Luca de Alfaro](https://luca.dealfaro.com/), [Elena Baralis](https://dbdmg.polito.it/wordpress/people/elena-baralis/). In Proceedings of the 2021 ACM SIGMOD Conference, 2021.

You can find more papers in the [project page](https://divexplorer.github.io/).

## Code Contributors

Project lead:

- [Eliana Pastor](https://github.com/elianap)

Other contributors: 

- [Luca de Alfaro](https://luca.dealfaro.com/)

Refer to [CONTRIBUTING.md](CONTRIBUTING.md) for  info on contributing and releases/pre-releases.

            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "DivExplorer",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "Pandas,Fairness,Subgroup Analysis,Data Mining",
    "author": "",
    "author_email": "Eliana Pastor <eliana.pastor@polito.it>, Luca de Alfaro <luca@ucsc.edu>",
    "download_url": "https://files.pythonhosted.org/packages/dc/7a/ddc0a5e3448846e718a7727b223a574e54769821a8f86d0ff53908765ecb/DivExplorer-0.2.1.tar.gz",
    "platform": null,
    "description": "[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/divexplorer/divexplorer/main.svg)](https://results.pre-commit.ci/latest/github/divexplorer/divexplorer/main)\n[![PyPI](https://img.shields.io/pypi/v/divexplorer)](https://pypi.org/project/divexplorer/)\n[![Downloads](https://pepy.tech/badge/divexplorer)](https://pepy.tech/project/divexplorer)\n\n# DivExplorer\n\n- [DivExplorer](#divexplorer)\n  - [Installation](#installation)\n  - [Usage](#usage)\n    - [Notebooks](#notebooks)\n    - [Package](#package)\n  - [Paper](#paper)\n  - [Contributing](#contributing)\n\nMachine learning models may perform differently on different data subgroups. We propose the notion of divergence over itemsets (i.e., conjunctions of simple predicates) as a measure of different classification behavior on data subgroups, and the use of frequent pattern mining techniques for their identification. We quantify the contribution of different attribute values to divergence with the notion of Shapley values to identify both critical and peculiar behaviors of attributes.\nSee our [paper](https://divexplorer.github.io/static/DivExplorer.pdf) and our [project page](https://divexplorer.github.io/) for all the details.\n\n## Installation\n\nInstall using [pip](http://www.pip-installer.org/en/latest) with:\n\n<pre>\npip install divexplorer\n</pre>\n\nor, download a wheel or source archive from [PyPI](https://pypi.org/project/divexplorer/).\n\n## Example Notebooks\n\nThis [notebook](https://github.com/divexplorer/divexplorer/blob/main/notebooks/DivExplorerExample.ipynb) gives an example of how to use DivExplorer to find divergent subgroups in datasets and in the predictions of a classifier.\nYou can also [run the notebook directly on Colab](https://colab.research.google.com/drive/1lDqqssBusiFHjgR6EciuWNT55hO4_X0o?usp=sharing). \n\n## Quick Start\n\nDivExplorer works on Pandas datasets.  Here we load an example one, and discretize in coarser ranges one of its attributes. \n\n```python\nimport pandas as pd\n\ndf_census = pd.read_csv('https://raw.githubusercontent.com/divexplorer/divexplorer/main/datasets/census_income.csv')\ndf_census[\"AGE_RANGE\"] = df_census.apply(lambda row : 10 * (row[\"A_AGE\"] // 10), axis=1)\n```\n\nWe can then find the data subgroups that have highest income divergence, using the `DivergenceExplorer` class as follows: \n\n```python\nfrom divexplorer import DivergenceExplorer\n\nfp_diver = DivergenceExplorer(df_census)\nsubgroups = fp_diver.get_pattern_divergence(min_support=0.001, quantitative_outcomes=[\"PTOTVAL\"])\nsubgroups.sort_values(by=\"PTOTVAL_div\", ascending=False).head(10)\n```\n\n### Finding subgroups with divergent performance in classifiers\n\nFor classifiers, it may be of interest to find the subgroups with the highest (or lowest) divergence in characteristics such as false positive rates, etc.  Here is how to do it for the false-positive rate in a COMPAS-derived classifier. \n\n```python\ncompas_df = pd.read_csv('https://raw.githubusercontent.com/divexplorer/divexplorer/main/datasets/compas_discretized.csv')\n```\n\nWe generate an `fp` column whose average will give the false-positive rate, like so: \n\n```python\nfrom divexplorer.outcomes import get_false_positive_rate_outcome\n\ny_trues = compas_df[\"class\"]\ny_preds = compas_df[\"predicted\"]\n\ncompas_df['fp'] =  get_false_positive_rate_outcome(y_trues, y_preds)\n```\n\nThe `fp` column has values: \n\n* 1, if the data is a false positive (`class` is 0 and `predicted` is 1)\n* 0, if the data is a true negative (`class` is 0 and `predicted` is 0). \n* NaN, if the class is positive (`class` is 1).\n\nWe use Nan for `class` 1 data, to exclude those data from the average, so that the column average is the false-positive rate.\nWe can then find the most divergent groups as in the previous example, noting that here we use `boolean_outcomes` rather than `quantitative_outcomes` because `fp` is boolean: \n\n```python\nfp_diver = DivergenceExplorer(compas_df)\n\nattributes = ['race', '#prior', 'sex', 'age']\nFP_fm = fp_diver.get_pattern_divergence(min_support=0.1, attributes=attributes, \n                                        boolean_outcomes=['fp'])\nFP_fm.sort_values(by=\"fp_div\", ascending=False).head(10)\n```\n\nNote how we specify the attributes that can be used to define subgroups. \n\n### Analyzing subgroups via Shapley values\n\nIf we want to analyze what factors contribute to the divergence of a particular subgroup, we can do so via Shapley values: \n\n```python\nfp_details = DivergencePatternProcessor(FP_fm, 'fp')\n\npattern = fp_details.patterns['itemset'].iloc[37]\nfp_details.shapley_value(pattern)\n```\n\n### Pruning redundant subgroups\n\nIf you get too many subgroups, you can prune redundant ones via _redundancy pruning_. \nThis prunes a pattern $\\beta$ if there is a pattern $\\alpha$, subset of $\\beta$, with a divergence difference below a threshold. \n\n```python\ndf_pruned = fp_details.redundancy_pruning(th_redundancy=0.01)\ndf_pruned.sort_values(\"fp_div\", ascending=False).head(5)\n```\n\n## Papers\n\nThe original paper is:\n\n> [Looking for Trouble: Analyzing Classifier Behavior via Pattern Divergence](https://divexplorer.github.io/static/DivExplorer.pdf). [Eliana Pastor](https://github.com/elianap), [Luca de Alfaro](https://luca.dealfaro.com/), [Elena Baralis](https://dbdmg.polito.it/wordpress/people/elena-baralis/). In Proceedings of the 2021 ACM SIGMOD Conference, 2021.\n\nYou can find more papers in the [project page](https://divexplorer.github.io/).\n\n## Code Contributors\n\nProject lead:\n\n- [Eliana Pastor](https://github.com/elianap)\n\nOther contributors: \n\n- [Luca de Alfaro](https://luca.dealfaro.com/)\n\nRefer to [CONTRIBUTING.md](CONTRIBUTING.md) for  info on contributing and releases/pre-releases.\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2021-23 Eliana Pastor  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "Analyze Pandas dataframes, and other tabular data (csv), to find subgroups of data with properties that diverge from those of the overall dataset",
    "version": "0.2.1",
    "project_urls": {
        "Documentation": "https://divexplorer.readthedocs.io/en/latest/",
        "Homepage": "https://divexplorer.github.io/",
        "Source": "https://github.com/DivExplorer/divexplorer"
    },
    "split_keywords": [
        "pandas",
        "fairness",
        "subgroup analysis",
        "data mining"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1d53f28b351a6fdb8113497302e9b99cc5151790d69e021c7305040663aa774f",
                "md5": "b491489e813bd0e58a38b37bfcacd7d6",
                "sha256": "ab57c53ecbebffe5d1459a36e7334ce71e12a094953940c2313cc5b746825f6a"
            },
            "downloads": -1,
            "filename": "DivExplorer-0.2.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b491489e813bd0e58a38b37bfcacd7d6",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 20541,
            "upload_time": "2023-11-10T19:37:44",
            "upload_time_iso_8601": "2023-11-10T19:37:44.441633Z",
            "url": "https://files.pythonhosted.org/packages/1d/53/f28b351a6fdb8113497302e9b99cc5151790d69e021c7305040663aa774f/DivExplorer-0.2.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "dc7addc0a5e3448846e718a7727b223a574e54769821a8f86d0ff53908765ecb",
                "md5": "9d2f525af029f8d922a06ca03e2d9ae9",
                "sha256": "aeca4221c889ddc0708bcc3fe3946019cdf234a4ec4d404a5c789cb92c973c6f"
            },
            "downloads": -1,
            "filename": "DivExplorer-0.2.1.tar.gz",
            "has_sig": false,
            "md5_digest": "9d2f525af029f8d922a06ca03e2d9ae9",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 17886,
            "upload_time": "2023-11-10T19:37:45",
            "upload_time_iso_8601": "2023-11-10T19:37:45.901667Z",
            "url": "https://files.pythonhosted.org/packages/dc/7a/ddc0a5e3448846e718a7727b223a574e54769821a8f86d0ff53908765ecb/DivExplorer-0.2.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-11-10 19:37:45",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "DivExplorer",
    "github_project": "divexplorer",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "divexplorer"
}
        
Elapsed time: 0.13608s