From ce5c7d61118b73f0c580042515e7a28dfc5b983e Mon Sep 17 00:00:00 2001 From: dzungpham <23127003@student.hcmus.edu.vn> Date: Wed, 8 Apr 2026 22:28:32 +0700 Subject: [PATCH] feat(question): introduce Mahalanobis distance calculation exercise Add starter code, solution, tests and documentation for calculating Mahalanobis distance, including reference implementation, test generation script, and example materials. --- .../__pycache__/solution.cpython-313.pyc | Bin 0 -> 1865 bytes .../189_mahalanobis-distance/description.md | 10 ++ .../189_mahalanobis-distance/example.json | 5 + questions/189_mahalanobis-distance/example.md | 21 +++ .../generate_tests.py | 125 ++++++++++++++++++ questions/189_mahalanobis-distance/learn.md | 44 ++++++ questions/189_mahalanobis-distance/meta.json | 12 ++ .../189_mahalanobis-distance/solution.py | 34 +++++ .../189_mahalanobis-distance/starter_code.py | 23 ++++ questions/189_mahalanobis-distance/tests.json | 34 +++++ 10 files changed, 308 insertions(+) create mode 100644 questions/189_mahalanobis-distance/__pycache__/solution.cpython-313.pyc create mode 100644 questions/189_mahalanobis-distance/description.md create mode 100644 questions/189_mahalanobis-distance/example.json create mode 100644 questions/189_mahalanobis-distance/example.md create mode 100644 questions/189_mahalanobis-distance/generate_tests.py create mode 100644 questions/189_mahalanobis-distance/learn.md create mode 100644 questions/189_mahalanobis-distance/meta.json create mode 100644 questions/189_mahalanobis-distance/solution.py create mode 100644 questions/189_mahalanobis-distance/starter_code.py create mode 100644 questions/189_mahalanobis-distance/tests.json diff --git a/questions/189_mahalanobis-distance/__pycache__/solution.cpython-313.pyc b/questions/189_mahalanobis-distance/__pycache__/solution.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..40da9aa97d9dca8dea2ebda55ce7230940b7ee9b GIT binary patch literal 1865 zcmb7EO>7%Q6rT0&I`-CSR1^?uRWh+c^iM)5kg1?q#%AogpepF#H~GXZckLIM3IG%hTiC4r@fk*1{mQA+eXmwki9+l8 z+L+X}c0{68UA`9-DKP~mhdueHIHOX2aE<_!1OOf+86QYUG@PLcu>4sSoKYu0RWT#z z2{&%MhU{{~Mm~oACWd*miEKoilI6jQ<@tz|F)U&KD#ipN82mCsq#`hNN~mPnmfs9m zsa0zDmP2L@BS&jq)`0!h6G{sA*(x|&l7?2>vF2x=uzC~(*Cp{^P z1eYpCyoxaNTvW!hp=N2Ju!&rpg(D?#rKeMQxFke`K@_xb4=Sa#}e!^ix8J?L#w zKb7kJLk5bBnCq8en)Ar+UQcD_Oip>4X^?uEBYx(fSLT&PpZ@4g=PIlt(uAVYcyUx< z1#eqOl#w@F1s<$Yryfv*A2Z?S4p~6uveW3*Pt~E^OG+`XYpyCRU|Ai!L?4Q2XvSHD zxGZX01lcvFT4b9Yx@eJ{U3;BUhce9-Bu!+3sTId(I^{MhOb-%iMyVKMRH&k2I5Dka zRjX`-3vKW$v6yTjPqcK;SN7&ows;9s&*3(UOZkhLw_Qvw@n*7dy|~rDUJ!k8Zefwn z(6AdbQdQA&>|UR_O*THnu^~C=bKID4%zK}2JD_s{#1FR;JL8?G7MZ@EIJ|qIbzwK( z%I~Gyi5GXKA0@!(*zWlc&wqaQ%X6Qe`}*WJ^Iy$hpK2d_>Bdxh{N;9HVdwb=vC)t5 zCvSY@>}|DUllPR#Cy&NJ{LpT^75_DM{O8#5E{H^?AM|xEx0d&^?Zk=qraL+(|KW*= z_`yVO5!_llb9Pa^y`b>j)R`WP04l~78|hC6Dwu;9z6V_n0ex0H$6l#Bm4=O9rN{VH z41I5&Zyi-pl;6NJ9c@BMUXOfdd~0+7hc}Wxq;IAJ_+#>?^qn5O_s;rb@k) float: + """ + Calculate the Mahalanobis distance between a point and a probability distribution. + + Args: + point (np.ndarray): A 1D numpy array representing the point in the feature space. + Shape: (n_features,) + mean (np.ndarray): A 1D numpy array representing the mean of the distribution. + Shape: (n_features,) + cov_matrix (np.ndarray): A 2D numpy array representing the covariance matrix. + Shape: (n_features, n_features) + + Returns: + float: The Mahalanobis distance, computed as sqrt((point - mean)^T * cov_matrix^(-1) * (point - mean)) + A scalar representing how many standard deviations the point is from the mean, + accounting for correlation between features. + + """ + # Compute deviation vector + diff = point - mean + + # Compute inverse of covariance matrix + try: + inv_cov = np.linalg.inv(cov_matrix) + except np.linalg.LinAlgError: + # Handle singular covariance matrix using pseudo-inverse + inv_cov = np.linalg.pinv(cov_matrix) + + # Compute Mahalanobis distance: sqrt((x - mu)^T * Sigma^(-1) * (x - mu)) + distance = np.sqrt(np.dot(np.dot(diff, inv_cov), diff)) + + return round(float(distance), 4) diff --git a/questions/189_mahalanobis-distance/starter_code.py b/questions/189_mahalanobis-distance/starter_code.py new file mode 100644 index 00000000..9db6c9f3 --- /dev/null +++ b/questions/189_mahalanobis-distance/starter_code.py @@ -0,0 +1,23 @@ +import numpy as np + +def mahalanobis_distance(point: np.ndarray, mean: np.ndarray, cov_matrix: np.ndarray) -> float: + """ + Calculate the Mahalanobis distance between a point and a probability distribution. + + Args: + point (np.ndarray): A 1D numpy array representing the point in the feature space. + Shape: (n_features,) + mean (np.ndarray): A 1D numpy array representing the mean of the distribution. + Shape: (n_features,) + cov_matrix (np.ndarray): A 2D numpy array representing the covariance matrix. + Shape: (n_features, n_features) + + Returns: + float: The Mahalanobis distance, rounded to 4 decimal places. + Computed as sqrt((point - mean)^T * cov_matrix^(-1) * (point - mean)). + A scalar representing how many standard deviations the point is from the mean, + accounting for correlation between features. + + """ + # Your code here + pass diff --git a/questions/189_mahalanobis-distance/tests.json b/questions/189_mahalanobis-distance/tests.json new file mode 100644 index 00000000..3aa8bfc0 --- /dev/null +++ b/questions/189_mahalanobis-distance/tests.json @@ -0,0 +1,34 @@ +[ + { + "test": "print(mahalanobis_distance(np.array([3.0, 4.0]), np.array([0.0, 0.0]), np.array([[1.0, 0.0], [0.0, 1.0]])))", + "expected_output": "5.0" + }, + { + "test": "print(mahalanobis_distance(np.array([2.0, 2.0]), np.array([0.0, 0.0]), np.array([[4.0, 0.0], [0.0, 1.0]])))", + "expected_output": "2.2361" + }, + { + "test": "print(mahalanobis_distance(np.array([1.0, 1.0]), np.array([0.0, 0.0]), np.array([[2.0, 1.0], [1.0, 2.0]])))", + "expected_output": "0.8165" + }, + { + "test": "print(mahalanobis_distance(np.array([5.0, 3.0, 2.0]), np.array([1.0, 1.0, 1.0]), np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])))", + "expected_output": "4.5826" + }, + { + "test": "print(mahalanobis_distance(np.array([2.0, 2.0, 2.0]), np.array([0.0, 0.0, 0.0]), np.array([[2.0, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 2.0]])))", + "expected_output": "2.4495" + }, + { + "test": "print(mahalanobis_distance(np.array([1.0, 2.0]), np.array([1.0, 2.0]), np.array([[1.0, 0.0], [0.0, 1.0]])))", + "expected_output": "0.0" + }, + { + "test": "print(mahalanobis_distance(np.array([1.0, 2.0, 3.0, 4.0]), np.array([0.0, 0.0, 0.0, 0.0]), np.eye(4)))", + "expected_output": "5.4772" + }, + { + "test": "print(mahalanobis_distance(np.array([-2.0, 3.0]), np.array([1.0, 1.0]), np.array([[1.0, 0.5], [0.5, 1.0]])))", + "expected_output": "5.0332" + } +] \ No newline at end of file