{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Map data to a normal distribution\n\n.. currentmodule:: sklearn.preprocessing\n\nThis example demonstrates the use of the Box-Cox and Yeo-Johnson transforms\nthrough :class:`~PowerTransformer` to map data from various\ndistributions to a normal distribution.\n\nThe power transform is useful as a transformation in modeling problems where\nhomoscedasticity and normality are desired. Below are examples of Box-Cox and\nYeo-Johnwon applied to six different probability distributions: Lognormal,\nChi-squared, Weibull, Gaussian, Uniform, and Bimodal.\n\nNote that the transformations successfully map the data to a normal\ndistribution when applied to certain datasets, but are ineffective with others.\nThis highlights the importance of visualizing the data before and after\ntransformation.\n\nAlso note that even though Box-Cox seems to perform better than Yeo-Johnson for\nlognormal and chi-squared distributions, keep in mind that Box-Cox does not\nsupport inputs with negative values.\n\nFor comparison, we also add the output from\n:class:`~QuantileTransformer`. It can force any arbitrary\ndistribution into a gaussian, provided that there are enough training samples\n(thousands). Because it is a non-parametric method, it is harder to interpret\nthan the parametric ones (Box-Cox and Yeo-Johnson).\n\nOn \"small\" datasets (less than a few hundred points), the quantile transformer\nis prone to overfitting. The use of the power transform is then recommended.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# Authors: The scikit-learn developers\n# SPDX-License-Identifier: BSD-3-Clause\n\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import PowerTransformer, QuantileTransformer\n\nN_SAMPLES = 1000\nFONT_SIZE = 6\nBINS = 30\n\n\nrng = np.random.RandomState(304)\nbc = PowerTransformer(method=\"box-cox\")\nyj = PowerTransformer(method=\"yeo-johnson\")\n# n_quantiles is set to the training set size rather than the default value\n# to avoid a warning being raised by this example\nqt = QuantileTransformer(\n    n_quantiles=500, output_distribution=\"normal\", random_state=rng\n)\nsize = (N_SAMPLES, 1)\n\n\n# lognormal distribution\nX_lognormal = rng.lognormal(size=size)\n\n# chi-squared distribution\ndf = 3\nX_chisq = rng.chisquare(df=df, size=size)\n\n# weibull distribution\na = 50\nX_weibull = rng.weibull(a=a, size=size)\n\n# gaussian distribution\nloc = 100\nX_gaussian = rng.normal(loc=loc, size=size)\n\n# uniform distribution\nX_uniform = rng.uniform(low=0, high=1, size=size)\n\n# bimodal distribution\nloc_a, loc_b = 100, 105\nX_a, X_b = rng.normal(loc=loc_a, size=size), rng.normal(loc=loc_b, size=size)\nX_bimodal = np.concatenate([X_a, X_b], axis=0)\n\n\n# create plots\ndistributions = [\n    (\"Lognormal\", X_lognormal),\n    (\"Chi-squared\", X_chisq),\n    (\"Weibull\", X_weibull),\n    (\"Gaussian\", X_gaussian),\n    (\"Uniform\", X_uniform),\n    (\"Bimodal\", X_bimodal),\n]\n\ncolors = [\"#D81B60\", \"#0188FF\", \"#FFC107\", \"#B7A2FF\", \"#000000\", \"#2EC5AC\"]\n\nfig, axes = plt.subplots(nrows=8, ncols=3, figsize=plt.figaspect(2))\naxes = axes.flatten()\naxes_idxs = [\n    (0, 3, 6, 9),\n    (1, 4, 7, 10),\n    (2, 5, 8, 11),\n    (12, 15, 18, 21),\n    (13, 16, 19, 22),\n    (14, 17, 20, 23),\n]\naxes_list = [(axes[i], axes[j], axes[k], axes[l]) for (i, j, k, l) in axes_idxs]\n\n\nfor distribution, color, axes in zip(distributions, colors, axes_list):\n    name, X = distribution\n    X_train, X_test = train_test_split(X, test_size=0.5)\n\n    # perform power transforms and quantile transform\n    X_trans_bc = bc.fit(X_train).transform(X_test)\n    lmbda_bc = round(bc.lambdas_[0], 2)\n    X_trans_yj = yj.fit(X_train).transform(X_test)\n    lmbda_yj = round(yj.lambdas_[0], 2)\n    X_trans_qt = qt.fit(X_train).transform(X_test)\n\n    ax_original, ax_bc, ax_yj, ax_qt = axes\n\n    ax_original.hist(X_train, color=color, bins=BINS)\n    ax_original.set_title(name, fontsize=FONT_SIZE)\n    ax_original.tick_params(axis=\"both\", which=\"major\", labelsize=FONT_SIZE)\n\n    for ax, X_trans, meth_name, lmbda in zip(\n        (ax_bc, ax_yj, ax_qt),\n        (X_trans_bc, X_trans_yj, X_trans_qt),\n        (\"Box-Cox\", \"Yeo-Johnson\", \"Quantile transform\"),\n        (lmbda_bc, lmbda_yj, None),\n    ):\n        ax.hist(X_trans, color=color, bins=BINS)\n        title = \"After {}\".format(meth_name)\n        if lmbda is not None:\n            title += \"\\n$\\\\lambda$ = {}\".format(lmbda)\n        ax.set_title(title, fontsize=FONT_SIZE)\n        ax.tick_params(axis=\"both\", which=\"major\", labelsize=FONT_SIZE)\n        ax.set_xlim([-3.5, 3.5])\n\n\nplt.tight_layout()\nplt.show()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.11.14"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}