{"id":17125457,"url":"https://github.com/daleroberts/hdmedians","last_synced_at":"2025-04-10T02:23:20.132Z","repository":{"id":19611622,"uuid":"80585917","full_name":"daleroberts/hdmedians","owner":"daleroberts","description":"High-dimensional medians (medoid, geometric median, etc.). Fast implementations in Python.","archived":false,"fork":false,"pushed_at":"2021-12-18T10:31:20.000Z","size":1945,"stargazers_count":69,"open_issues_count":3,"forks_count":14,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-04-23T23:07:25.381Z","etag":null,"topics":["high-dimensional-data","machine-learning","median","python","statistics"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daleroberts.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-02-01T03:22:05.000Z","updated_at":"2024-04-19T12:54:49.000Z","dependencies_parsed_at":"2022-08-24T17:50:18.748Z","dependency_job_id":null,"html_url":"https://github.com/daleroberts/hdmedians","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daleroberts%2Fhdmedians","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daleroberts%2Fhdmedians/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daleroberts%2Fhdmedians/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daleroberts%2Fhdmedians/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daleroberts","download_url":"https://codeload.github.com/daleroberts/hdmedians/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248143333,"owners_count":21054760,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["high-dimensional-data","machine-learning","median","python","statistics"],"created_at":"2024-10-14T18:44:56.509Z","updated_at":"2025-04-10T02:23:20.110Z","avatar_url":"https://github.com/daleroberts.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hdmedians\n\nDid you know there is no unique way to mathematically extend the concept of a\n[median](https://en.wikipedia.org/wiki/Median) to higher dimensions?\n\nVarious definitions for a **high-dimensional median** exist and this Python\npackage provides a number of fast implementations of these definitions.\nMedians are extremely useful due to their high breakdown point (up to 50%\ncontamination) and have a number of nice applications in machine learning,\ncomputer vision, and high-dimensional statistics.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://rawgit.com/daleroberts/hdmedians/master/docs/fig1.svg\" width=600px height=180px /\u003e\n\u003c/p\u003e\n\nThis package currently has implementations of [medoid](#medoid) and [geometric\nmedian](#geometric-median) with support for missing data using `NaN`. \n\n### Installation\n\nThe latest version of the package is always available on [pypi](https://pypi.python.org/pypi/hdmedians), \nso can be easily installed by typing:\n```{sh}\npip3 install hdmedians\n```\n\n## Medoid\n\nGiven a finite set \u003cimg src=\"https://rawgit.com/daleroberts/hdmedians/master/docs/97c2c0ac5d7c079601abd56a54c9475c.svg?invert_in_darkmode\" align=middle width=12.577454999999999pt height=22.027169999999977pt/\u003e of \u003cimg src=\"https://rawgit.com/daleroberts/hdmedians/master/docs/2ec6e630f199f589a2402fdf3e0289d5.svg?invert_in_darkmode\" align=middle width=8.008308pt height=15.034140000000015pt/\u003e-dimensional observation vectors \u003cimg src=\"https://rawgit.com/daleroberts/hdmedians/master/docs/8ce46e21b12b0c15b3683b17029ce564.svg?invert_in_darkmode\" align=middle width=111.746745pt height=22.698719999999994pt/\u003e, \nthe [medoid](https://en.wikipedia.org/wiki/Medoid) \u003cimg src=\"https://rawgit.com/daleroberts/hdmedians/master/docs/273457f251a6f8920e7b6c485c28b74f.svg?invert_in_darkmode\" align=middle width=13.642034999999998pt height=15.721860000000007pt/\u003e of these observations is given by\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://rawgit.com/daleroberts/hdmedians/master/docs/e2ab5aaffe776fde1073a90f83f75a77.svg?invert_in_darkmode\" align=middle width=202.62825pt height=45.437205pt/\u003e\u003c/p\u003e\n\nThe current implementation of `medoid` is in vectorized Python and can handle\nany data type supported by\n[ndarray](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.html).\nIf you would like the algorithm to take care of missing values encoded as `nan`\nthen you can use the `nanmedoid` function.\n\n### Examples\n\nCreate an 6 x 10 array of random integer observations.\n```{python}\n\u003e\u003e\u003e import numpy as np\n\u003e\u003e\u003e X = np.random.randint(100, size=(6, 10))\narray([[12,  9, 61, 76,  2, 17, 12, 11, 26,  0],\n       [65, 72,  7, 64, 21, 92, 51, 48,  9, 65],\n       [39,  7, 50, 56, 29, 79, 47, 45, 10, 52],\n       [70, 12, 23, 97, 86, 14, 42, 90, 15, 16],\n       [13,  7,  2, 47, 80, 53, 23, 59,  7, 15],\n       [83,  2, 40, 12, 22, 75, 69, 61, 28, 53]])\n```\n\nFind the medoid, taking the last axis as the number of observations.\n```{python}\n\u003e\u003e\u003e import hdmedians as hd\n\u003e\u003e\u003e hd.medoid(X)\narray([12, 51, 47, 42, 23, 69])\n```\n\nTake the first axis as the number of observations.\n```{python}\n\u003e\u003e\u003e hd.medoid(X, axis=0)\narray([39,  7, 50, 56, 29, 79, 47, 45, 10, 52])\n```\n\nSince the medoid is one of the observations, the `medoid` function has the ability to only return the index if required.\n```{python}\n\u003e\u003e\u003e hd.medoid(X, indexonly=True)\n6\n\u003e\u003e\u003e X[:,6]\narray([12, 51, 47, 42, 23, 69])\n```\n\n## Geometric Median\n\nThe [geometric median](https://en.wikipedia.org/wiki/Geometric_median) is also known as the 1-median, spatial median,\nEuclidean minisum, or Torricelli point. Given a finite set \u003cimg src=\"https://rawgit.com/daleroberts/hdmedians/master/docs/97c2c0ac5d7c079601abd56a54c9475c.svg?invert_in_darkmode\" align=middle width=12.577454999999999pt height=22.027169999999977pt/\u003e of \u003cimg src=\"https://rawgit.com/daleroberts/hdmedians/master/docs/2ec6e630f199f589a2402fdf3e0289d5.svg?invert_in_darkmode\" align=middle width=8.008308pt height=15.034140000000015pt/\u003e-dimensional observation vectors \u003cimg src=\"https://rawgit.com/daleroberts/hdmedians/master/docs/8ce46e21b12b0c15b3683b17029ce564.svg?invert_in_darkmode\" align=middle width=111.746745pt height=22.698719999999994pt/\u003e, \nthe geometric median \u003cimg src=\"https://rawgit.com/daleroberts/hdmedians/master/docs/fb2c407771af04095047a75aab1127e2.svg?invert_in_darkmode\" align=middle width=9.973589999999998pt height=22.747889999999988pt/\u003e of these observations is given by\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://rawgit.com/daleroberts/hdmedians/master/docs/24a6cad3853187faa18a0cf58c6515c8.svg?invert_in_darkmode\" align=middle width=204.38385pt height=45.437205pt/\u003e\u003c/p\u003e\nNote there is a subtle difference between the definition of the geometric median and the medoid: the search space \nfor the solution differs and has the effect that the medoid returns one of the true observations whereas the geometric median can be described \nas a synthetic (not physically observed) observation.\n\nThe current implementation of `geomedian` uses Cython and can handle `float64`\nor `float32`. If you would like the algorithm to take care of missing values\nencoded as `nan` then you can use the `nangeomedian` function.\n\n### Examples\n\nCreate an 6 x 10 array of random `float64` observations.\n```{python}\n\u003e\u003e\u003e import numpy as np\n\u003e\u003e\u003e np.set_printoptions(precision=4, linewidth=200)\n\u003e\u003e\u003e X = np.random.normal(1, size=(6, 10))\narray([[ 1.1079,  0.5763,  0.3072,  1.2205,  0.8596, -1.5082,  2.5955,  2.8251,  1.5908,  0.4575],\n       [ 1.555 ,  1.7903,  1.213 ,  1.1285,  0.0461, -0.4929, -0.1158,  0.5879,  1.5807,  0.5828],\n       [ 2.1583,  3.4429,  0.4166,  1.0192,  0.8308, -0.1468,  2.6329,  2.2239,  0.2168,  0.8783],\n       [ 0.7382,  1.9453,  0.567 ,  0.6797,  1.1654, -0.1556,  0.9934,  0.1857,  1.369 ,  2.1855],\n       [ 0.1727,  0.0835,  0.5416,  1.4416,  1.6921,  1.6636,  1.6421,  1.0687,  0.6075, -0.0301],\n       [ 2.6654,  1.6741,  1.1568,  1.3092,  1.6944,  0.2574,  2.8604,  1.6102,  0.4301, -0.3876]])\n\u003e\u003e\u003e X.dtype\ndtype('float64')\n```\n\nFind the geometric median, taking the last axis as the number of observations.\n```{python}\n\u003e\u003e\u003e import hdmedians as hd\n\u003e\u003e\u003e hd.geomedian(X)\narray([ 1.0733,  0.8974,  1.1935,  0.9122,  0.9975,  1.3422])\n```\n\nTake the first axis as the number of observations.\n```{python}\n\u003e\u003e\u003e hd.geomedian(X, axis=0)\narray([ 1.4581,  1.6377,  0.7147,  1.1257,  1.0493, -0.091 ,  1.7907,  1.4168,  0.9587,  0.6195])\n```\n\nConvert to `float32` and compute the geometric median.\n```{python}\n\u003e\u003e\u003e X = X.astype(np.float32)\n\u003e\u003e\u003e m = hd.geomedian(X)\n```\n\n## References\n\n  * Small, C. G. (1990). [A survey of multidimensional medians](http://www.jstor.org/stable/1403809). *International Statistical Review/Revue Internationale de Statistique*, 263-277.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaleroberts%2Fhdmedians","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaleroberts%2Fhdmedians","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaleroberts%2Fhdmedians/lists"}