{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\nGroupLasso as a transformer\n============================\n\nA sample script to demonstrate how the group lasso estimators can be used\nfor variable selection in a scikit-learn pipeline.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Setup\n-----\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from group_lasso import GroupLasso\nfrom sklearn.linear_model import Ridge\nfrom sklearn.metrics import r2_score\nfrom sklearn.pipeline import Pipeline\nfrom utils import (\n    get_groups_from_group_sizes,\n    generate_group_lasso_coefficients,\n)\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n\nnp.random.seed(0)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Set dataset parameters\n----------------------\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "group_sizes = [np.random.randint(10, 20) for i in range(50)]\nactive_groups = [np.random.randint(2) for _ in group_sizes]\ngroups = get_groups_from_group_sizes(group_sizes)\nnum_coeffs = sum(group_sizes)\nnum_datapoints = 10000\nnoise_std = 20"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Generate data matrix\n--------------------\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "X = np.random.standard_normal((num_datapoints, num_coeffs))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Generate coefficients\n---------------------\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "w = np.concatenate(\n    [\n        np.random.standard_normal(group_size) * is_active\n        for group_size, is_active in zip(group_sizes, active_groups)\n    ]\n)\nw = w.reshape(-1, 1)\ntrue_coefficient_mask = w != 0\nintercept = 2"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Generate regression targets\n---------------------------\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "y_true = X @ w + intercept\ny = y_true + np.random.randn(*y_true.shape) * noise_std"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "View noisy data and compute maximum R^2\n---------------------------------------\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "plt.figure()\nplt.plot(y, y_true, \".\")\nplt.xlabel(\"Noisy targets\")\nplt.ylabel(\"Noise-free targets\")\n# Use noisy y as true because that is what we would have access\n# to in a real-life setting.\nR2_best = r2_score(y, y_true)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Generate pipeline and train it\n------------------------------\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "pipe = Pipeline(\n    memory=None,\n    steps=[\n        (\n            \"variable_selection\",\n            GroupLasso(\n                groups=groups,\n                group_reg=1.3,\n                subsampling_scheme=1,\n                supress_warning=True,\n            ),\n        ),\n        (\"regressor\", Ridge(alpha=0.1)),\n    ],\n)\npipe.fit(X, y)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Extract results and compute performance metrics\n-----------------------------------------------\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# Extract from pipeline\nyhat = pipe.predict(X)\nsparsity_mask = pipe[\"variable_selection\"].sparsity_mask\ncoef = pipe[\"regressor\"].coef_.T\n\n# Construct full coefficient vector\nw_hat = np.zeros_like(w)\nw_hat[sparsity_mask] = coef\n\nR2 = r2_score(y, yhat)\ntrue_R2 = r2_score(y_true, yhat)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Print performance metrics\n-------------------------\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "print(f\"Number variables: {len(sparsity_mask)}\")\nprint(f\"Number of chosen variables: {sparsity_mask.sum()}\")\nprint(f\"R^2: {R2}, best possible R^2 = {R2_best}\")\nprint(f\"R^2 compared to noise-free data: {R2}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Visualise regression coefficients\n---------------------------------\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "for i in range(w.shape[1]):\n    plt.figure()\n    plt.plot(w[:, i], \".\", label=\"True weights\")\n    plt.plot(w_hat[:, i], \".\", label=\"Estimated weights\")\n\nplt.figure()\nplt.plot([w.min(), w.max()], [coef.min(), coef.max()], \"gray\")\nplt.scatter(w, w_hat, s=10)\nplt.ylabel(\"Learned coefficients\")\nplt.xlabel(\"True coefficients\")\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.7.4"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}