{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes, you need to pick up the \$N\$-th extremal values in a mutli-dimensional matrix. \n", "\n", "Let's suppose it is represented as a ``nd-array`` (here, I further suppose you are using the numpy library from the python language). Finding extremal values is easy with ``argsort`` but this function operated on 1d vectors... Juggling around indices is sometimes not such an easy task, but luckily, we have the ``unravel_index`` function.\n", "\n", "Let's unwrap an easy solution combining these functions:\n", "\n", "\n", "\n", "Let's first initialize the notebook:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's first a dummy 3-D array:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[[20 6]\n", " [23 18]\n", " [ 0 5]]\n", "\n", " [[10 3]\n", " [13 1]\n", " [11 8]]\n", "\n", " [[21 7]\n", " [22 14]\n", " [19 12]]\n", "\n", " [[17 9]\n", " [ 2 15]\n", " [16 4]]]\n" ] } ], "source": [ "x = np.array([[0, 5, 4], [2, 1, 3]])\n", "x = np.arange(2*3*4).reshape((4, 3, 2))\n", "x = np.random.permutation(np.arange(2*3*4)).reshape((4, 3, 2))\n", "print (x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Which we can represent as a 1-d array (a vector):" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[20 6 23 18 0 5 10 3 13 1 11 8 21 7 22 14 19 12 17 9 2 15 16 4]\n" ] } ], "source": [ "print (x.ravel())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We may now find the list of indices to sort it:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 4 9 20 7 23 5 1 13 11 19 6 10 17 8 15 21 22 18 3 16 0 12 14 2]\n" ] } ], "source": [ "print (np.argsort(x.ravel()))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And we verify that the entries are indeed sorted:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]\n" ] } ], "source": [ "print (x.ravel()[np.argsort(x.ravel())])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To go back to the ``nd-array``, we use the ``unraval_index`` function:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on built-in function unravel_index in module numpy.core.multiarray:\n", "\n", "unravel_index(...)\n", " unravel_index(indices, dims, order='C')\n", " \n", " Converts a flat index or array of flat indices into a tuple\n", " of coordinate arrays.\n", " \n", " Parameters\n", " ----------\n", " indices : array_like\n", " An integer array whose elements are indices into the flattened\n", " version of an array of dimensions ``dims``. Before version 1.6.0,\n", " this function accepted just one index value.\n", " dims : tuple of ints\n", " The shape of the array to use for unraveling ``indices``.\n", " order : {'C', 'F'}, optional\n", " Determines whether the indices should be viewed as indexing in\n", " row-major (C-style) or column-major (Fortran-style) order.\n", " \n", " .. versionadded:: 1.6.0\n", " \n", " Returns\n", " -------\n", " unraveled_coords : tuple of ndarray\n", " Each array in the tuple has the same shape as the ``indices``\n", " array.\n", " \n", " See Also\n", " --------\n", " ravel_multi_index\n", " \n", " Examples\n", " --------\n", " >>> np.unravel_index([22, 41, 37], (7,6))\n", " (array([3, 6, 6]), array([4, 5, 1]))\n", " >>> np.unravel_index([31, 41, 13], (7,6), order='F')\n", " (array([3, 6, 6]), array([4, 5, 1]))\n", " \n", " >>> np.unravel_index(1621, (6,7,8,9))\n", " (3, 1, 4, 1)\n", "\n" ] } ], "source": [ "help(np.unravel_index)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(array([0, 1, 3, 1, 3, 0, 0, 2, 1, 3, 1, 1, 2, 1, 2, 3, 3, 3, 0, 2, 0, 2, 2,\n", " 0]), array([2, 1, 1, 0, 2, 2, 0, 0, 2, 0, 0, 2, 2, 1, 1, 1, 2, 0, 1, 2, 0, 0, 1,\n", " 1]), array([0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,\n", " 0]))\n" ] } ], "source": [ "print (np.unravel_index(np.argsort(x.ravel()), x.shape))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Such that we can now sort the whole array from the lowest to highest index:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]\n" ] } ], "source": [ "print (x[np.unravel_index(np.argsort(x.ravel()), x.shape)])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now pick just the ``datapoints`` extremal values of interest :" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false, "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(array([0, 1, 3, 1, 3, 0, 0, 2, 1, 3]), array([2, 1, 1, 0, 2, 2, 0, 0, 2, 0]), array([0, 1, 0, 1, 1, 1, 1, 1, 1, 1]))\n" ] } ], "source": [ "datapoints = 10\n", "print (np.unravel_index(np.argsort(x.ravel())[:datapoints], x.shape))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's now try with a more generic example :" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[[ 0.43933303 0.35481207]\n", " [ 0.04459993 0.65894333]\n", " [ 0.68128816 0.6476884 ]]\n", "\n", " [[ 0.45980888 0.79537777]\n", " [ 0.85516965 0.95558241]\n", " [ 0.26402052 0.25199538]]\n", "\n", " [[ 0.75092699 0.88245315]\n", " [ 0.39587322 0.69577732]\n", " [ 0.97255091 0.26780385]]\n", "\n", " [[ 0.45577996 0.49798838]\n", " [ 0.36976289 0.32772751]\n", " [ 0.28368218 0.85828921]]]\n" ] } ], "source": [ "x = np.random.rand(4, 3, 2)\n", "print (x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The indices for the ``datapoints`` extremal values of interest are :" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(array([0, 1, 1, 2, 3, 3, 0, 3, 2, 0]), array([1, 2, 2, 2, 2, 1, 0, 1, 1, 0]), array([0, 1, 0, 1, 0, 1, 1, 0, 0, 0]))\n" ] } ], "source": [ "print (np.unravel_index(np.argsort(x.ravel())[:datapoints], x.shape))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... which correspond to the minimal values of interest :" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 0.04459993 0.25199538 0.26402052 0.26780385 0.28368218 0.32772751\n", " 0.35481207 0.36976289 0.39587322 0.43933303]\n" ] } ], "source": [ "print (x[np.unravel_index(np.argsort(x.ravel())[:datapoints], x.shape)])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that it is also easy to pick the maximal values :" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(array([2, 1, 2, 3, 1, 1, 2, 2, 0, 0]), array([2, 1, 0, 2, 1, 0, 0, 1, 2, 1]), array([0, 1, 1, 1, 0, 1, 0, 1, 0, 1]))\n" ] } ], "source": [ "print (np.unravel_index(np.argsort(-x.ravel())[:datapoints], x.shape))" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "nikola": { "category": "", "date": "2016-11-17 18:07:37 UTC+01:00", "description": "", "link": "", "slug": "2016-11-17-finding-extremal-values-in-a-nd-array", "tags": "python, ipython, blog, numpy, open-science", "title": "2016-11-17 Finding extremal values in a nd-array", "type": "text" }, "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.5.2" } }, "nbformat": 4, "nbformat_minor": 0 }