{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# How to use joblib.Memory\n\nThis example illustrates the usage of :class:`joblib.Memory` with both\nfunctions and methods.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Without :class:`joblib.Memory`\n\n ``costly_compute`` emulates a computationally expensive process which later\n will benefit from caching using :class:`joblib.Memory`.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "import time\nimport numpy as np\n\n\ndef costly_compute(data, column_index=0):\n    \"\"\"Simulate an expensive computation\"\"\"\n    time.sleep(5)\n    return data[column_index]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Be sure to set the random seed to generate deterministic data. Indeed, if the\ndata is not deterministic, the :class:`joblib.Memory` instance will not be\nable to reuse the cache from one run to another.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "rng = np.random.RandomState(42)\ndata = rng.randn(int(1e5), 10)\nstart = time.time()\ndata_trans = costly_compute(data)\nend = time.time()\n\nprint('\\nThe function took {:.2f} s to compute.'.format(end - start))\nprint('\\nThe transformed data are:\\n {}'.format(data_trans))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Caching the result of a function to avoid recomputing\n\n If we need to call our function several time with the same input data, it is\n beneficial to avoid recomputing the same results over and over since it is\n expensive. :class:`joblib.Memory` enables to cache results from a function\n into a specific location.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from joblib import Memory\nlocation = './cachedir'\nmemory = Memory(location, verbose=0)\n\n\ndef costly_compute_cached(data, column_index=0):\n    \"\"\"Simulate an expensive computation\"\"\"\n    time.sleep(5)\n    return data[column_index]\n\n\ncostly_compute_cached = memory.cache(costly_compute_cached)\nstart = time.time()\ndata_trans = costly_compute_cached(data)\nend = time.time()\n\nprint('\\nThe function took {:.2f} s to compute.'.format(end - start))\nprint('\\nThe transformed data are:\\n {}'.format(data_trans))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "At the first call, the results will be cached. Therefore, the computation\ntime corresponds to the time to compute the results plus the time to dump the\nresults into the disk.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "start = time.time()\ndata_trans = costly_compute_cached(data)\nend = time.time()\n\nprint('\\nThe function took {:.2f} s to compute.'.format(end - start))\nprint('\\nThe transformed data are:\\n {}'.format(data_trans))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "At the second call, the computation time is largely reduced since the results\nare obtained by loading the data previously dumped to the disk instead of\nrecomputing the results.\n\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Using :class:`joblib.Memory` with a method\n\n :class:`joblib.Memory` is designed to work with functions with no side\n effects. When dealing with class, the computationally expensive part of a\n method has to be moved to a function and decorated in the class method.\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "def _costly_compute_cached(data, column):\n    time.sleep(5)\n    return data[column]\n\n\nclass Algorithm(object):\n    \"\"\"A class which is using the previous function.\"\"\"\n\n    def __init__(self, column=0):\n        self.column = column\n\n    def transform(self, data):\n        costly_compute = memory.cache(_costly_compute_cached)\n        return costly_compute(data, self.column)\n\n\ntransformer = Algorithm()\nstart = time.time()\ndata_trans = transformer.transform(data)\nend = time.time()\n\nprint('\\nThe function took {:.2f} s to compute.'.format(end - start))\nprint('\\nThe transformed data are:\\n {}'.format(data_trans))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "start = time.time()\ndata_trans = transformer.transform(data)\nend = time.time()\n\nprint('\\nThe function took {:.2f} s to compute.'.format(end - start))\nprint('\\nThe transformed data are:\\n {}'.format(data_trans))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "As expected, the second call to the ``transform`` method load the results\nwhich have been cached.\n\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Clean up cache directory\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "memory.clear(warn=False)"
      ]
    }
  ],
  "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.10.9"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}