Metadata-Version: 2.3
Name: syndat
Version: 0.13.9
Summary: A library for evaluation & visualization of synthetic data.
Keywords: synthetic-data,data-quality,data-visualization
Author: Tim Adams
Author-email: Tim Adams <tim.adams@scai.fraunhofer.de>
License: MIT License
         
         Copyright (c) 2023 Fraunhofer SCAI Bioinformatics Department
         
         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.
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3
Requires-Dist: pandas>=2.2.3
Requires-Dist: scikit-learn>=1.5.2
Requires-Dist: matplotlib>=3.9.2
Requires-Dist: seaborn>=0.13.0
Requires-Dist: shap>=0.48
Requires-Dist: plotnine>=0.13.6
Requires-Dist: numpy>=1.26.2
Requires-Dist: scipy>=1.11.4
Requires-Python: >=3.10, <3.14
Project-URL: Homepage, https://github.com/SCAI-BIO/syndat
Project-URL: Repository, https://github.com/SCAI-BIO/syndat
Project-URL: documentation, https://github.com/SCAI-BIO/syndat#readme
Project-URL: source, https://github.com/SCAI-BIO/syndat
Project-URL: tracker, https://github.com/SCAI-BIO/syndat/issues
Description-Content-Type: text/markdown

<picture align="left">
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/SCAI-BIO/syndat/refs/heads/main/docs/logo/syndat_white.svg">
  <img alt="Syndat Logo" src="https://raw.githubusercontent.com/SCAI-BIO/syndat/refs/heads/main/docs/logo/syndat.svg">
</picture>

<a href="https://doi.org/10.5281/zenodo.15791976"><img src="https://img.shields.io/badge/DOI-10.5281%2Fzenodo.15791976-blue.svg" alt="DOI"></a>&nbsp;<a href="https://github.com/SCAI-BIO/syndat/actions/workflows/tests.yaml"><img src="https://github.com/SCAI-BIO/syndat/actions/workflows/tests.yaml/badge.svg" alt="tests"></a>&nbsp;<a href="https://codecov.io/gh/SCAI-BIO/syndat"><img src="https://codecov.io/gh/SCAI-BIO/syndat/branch/main/graph/badge.svg" alt="codecov"></a>&nbsp;<a href="https://readthedocs.org/projects/syndat/"><img src="https://readthedocs.org/projects/syndat/badge/?version=latest&style=flat" alt="docs"></a>&nbsp;<a href="https://pypi.org/project/syndat/"><img src="https://img.shields.io/pypi/v/syndat" alt="version"></a>&nbsp;<a href="https://pepy.tech/projects/syndat"><img src="https://static.pepy.tech/personalized-badge/syndat?period=total&units=INTERNATIONAL_SYSTEM&left_color=GREY&right_color=BLUE&left_text=downloads" alt="PyPI Downloads"></a>

<a href="https://www.nfdi4health.de"><img src="https://img.shields.io/badge/Developed_in-NFDI4Health-1E88E5" alt="NFDI4Health"></a>&nbsp;<a href="https://www.ihi-synthia.eu"><img src="https://img.shields.io/badge/Extended_in-SYNTHIA-8E24AA" alt="SYNTHIA"></a>


# About

Syndat is a software package that provides basic functionalities for the evaluation and visualisation of synthetic data. Quality scores can be computed on 3 base metrics (Discrimation, Correlation and Distribution) and data may be visualized to inspect correlation structures or statistical distribution plots. 

Syndat also allows users to generate stratified and interpretable visualisations, including raincloud plots, GOF plots, and trajectory comparisons, offering deeper insights into the quality of synthetic clinical data across different subgroups.

# Installation

Install via pip:

```bash
pip install syndat
```

# Usage

## Fidelity metrics

### Jenson-Shannon Distance

The Jenson-Shannon distance is a measure of similarity between two probability distributions. In our case, we compute
probability distributions for each feature in the datasets and can thus compare the statistic feature 
similarity of two dataframes. 

It is bounded between 0 and 1, with 0 indicating identical distributions. 

### (Normalized) Correlation Difference

In addition to statistical similarity between the same features, we also want to make sure to preserve the correlations
across different features. The normalized correlation difference measures the similarity of the correlation matrix of 
two dataframes.

A low correlation difference near zero indicates that the correlation structure of the synthetic data is similar to the 
real data.

### Discriminator AUC

A classifier is trained to discriminate between real and synthetic data. Based on the Receiver Operating Characteristic 
(ROC) curve, we compute the area under the curve (AUC) as a measure of how well the classifier can distinguish between 
the two datasets. 

An AUC of 0.5 indicates that the classifier is unable to distinguish between the two datasets, while an AUC of 1.0 
indicates perfect discrimination.

Exemplary usage:

```python
import pandas as pd
from syndat.metrics import (
    jensen_shannon_distance,
    normalized_correlation_difference,
    discriminator_auc
)

real = pd.DataFrame({
    'feature1': [1, 2, 3, 4, 5],
    'feature2': ['A', 'B', 'A', 'B', 'C']
})

synthetic = pd.DataFrame({
    'feature1': [1, 2, 2, 3, 3],
    'feature2': ['A', 'B', 'A', 'C', 'C']
})

print(jensen_shannon_distance(real, synthetic))
>> {'feature1': 0.4990215421876156, 'feature2': 0.22141025172133794}

print(normalized_correlation_difference(real, synthetic))
>> 0.24571345029108108

print(discriminator_auc(real, synthetic))
>> 0.6
```

### Scoring Functions

For convenience and easier interpretation, a normalized score can be computed for each of the 
metrics instead:

```python
# JSD score is being aggregated over all features
distribution_similarity_score = syndat.scores.distribution(real, synthetic)
discrimination_score = syndat.scores.discrimination(real, synthetic)
correlation_score = syndat.scores.correlation(real, synthetic)
```

Scores are defined in a range of 0-100, with a higher score corresponding to better data fidelity.

## Visualization

Visualize real vs. synthetic data distributions, summary statistics and discriminating features:

```python
import pandas as pd
import syndat

real = pd.read_csv("real.csv")
synthetic = pd.read_csv("synthetic.csv")

# plot *all* feature distribution and store image files
syndat.visualization.plot_distributions(real, synthetic, store_destination="results/plots")
syndat.visualization.plot_correlations(real, synthetic, store_destination="results/plots")

# plot and display specific feature distribution plot
syndat.visualization.plot_numerical_feature("feature_xy", real, synthetic)
syndat.visualization.plot_numerical_feature("feature_xy", real, synthetic)

# plot a shap plot of differentiating feature for real and synthetic data
syndat.visualization.plot_shap_discrimination(real, synthetic)
```


## Postprocessing

Postprocess synthetic data to improve data fidelity:

```python
import pandas as pd
import syndat

real = pd.read_csv("real.csv")
synthetic = pd.read_csv("synthetic.csv")

# postprocess synthetic data
synthetic_post = syndat.postprocessing.assert_minmax(real, synthetic)
synthetic_post = syndat.postprocessing.normalize_float_precision(real, synthetic)
```

## Evaluation and Visualization of Synthetic Clinical Trial Data

An example demonstrating how to compute distribution, discrimination, and correlation scores, as well as how to generate stratified visualizations (gof, raincloud and other plots), is available in `examples/rct_example.py`.

# Acknowledgements

This work was done as part of the [NFDI4Health](https://www.nfdi4health.de) Consortium. 

It is currently also being extended as part of the [SYNTHIA](https://www.ihi-synthia.eu/) collaboration.


# Citation

If you use **Syndat** in your research, please cite as:

```bibtex
@article{Adams_On_the_fidelity_2025,
  author  = {Adams, Tim and Birkenbihl, Colin and Otte, Karen and
             Ng, Hwei Geok and Rieling, Jonas Adrian and
             Näher, Anatol-Fiete and Sax, Ulrich and
             Prasser, Fabian and Fröhlich, Holger},
  title   = {On the fidelity versus privacy and utility trade-off of synthetic patient data},
  journal = {iScience},
  volume  = {28},
  year    = {2025},
  doi     = {10.1016/j.isci.2025.112382}
}
```

