如何用Matlab的bsxfun函数编写切比雪夫与马氏距离代码?
Hey there! Let's work through your problem of replacing Euclidean distance with Chebyshev and Mahalanobis distances in your KNN implementation—using bsxfun for optimization, just like you wanted. I'll break down each distance with clear, tested code and explain where your initial max function approach might have gone wrong.
Chebyshev Distance Implementation with bsxfun
Chebyshev distance between two vectors is the maximum absolute difference of their corresponding elements. The key mistake in your initial attempt was likely not specifying the correct dimension for the max function (you probably took the global max instead of the max per sample pair).
Here's how to implement it efficiently with bsxfun:
% Example data: X = training set (n samples × d features), Y = test set (m samples × d features) X = randn(100, 5); % 100 training samples, 5 features Y = randn(20, 5); % 20 test samples, 5 features % Step 1: Broadcast to compute element-wise differences between all X-Y pairs % permute(Y, [3,2,1]) reshapes Y to 1×d×m, so bsxfun can match X's n×d shape diff_mat = bsxfun(@minus, X, permute(Y, [3, 2, 1])); % Step 2: Take absolute values, then max along the feature dimension (dimension 2) % squeeze removes singleton dimensions to get an n×m distance matrix chebyshev_dist = squeeze(max(abs(diff_mat), [], 2)); % Verify with Matlab's built-in function (for correctness) assert(all(all(abs(chebyshev_dist - pdist2(X, Y, 'chebychev')) < 1e-10)));
The max(..., [], 2) ensures we take the maximum difference per feature pair (not the entire matrix), which gives the correct Chebyshev distance for each training-test sample pair.
Mahalanobis Distance Implementation with bsxfun
Mahalanobis distance accounts for correlations between features using the covariance matrix of the training data. It's calculated as:
$$D(x,y) = \sqrt{(x-y)^T \Sigma^{-1} (x-y)}$$
where $\Sigma$ is the covariance matrix of the training set.
To optimize this with bsxfun (avoiding loops), we can expand the formula into matrix operations:
% Example data X = randn(100, 5); Y = randn(20, 5); % Step 1: Compute covariance matrix of training data (add small regularization to avoid singularity) cov_X = cov(X) + 1e-6 * eye(size(X, 2)); inv_cov = inv(cov_X); % Use pinv(cov_X) for more stability if needed % Step 2: Precompute terms for batch calculation x_inv_cov_x = sum((X * inv_cov) .* X, 2); % n×1 vector: x_i^T Σ⁻¹ x_i for each training sample y_inv_cov_y = sum((Y * inv_cov) .* Y, 2); % m×1 vector: y_k^T Σ⁻¹ y_k for each test sample xy_inv_cov = X * inv_cov * Y'; % n×m matrix: x_i^T Σ⁻¹ y_k for all pairs % Step 3: Use bsxfun to broadcast and compute squared Mahalanobis distances mahalanobis_sq = bsxfun(@plus, x_inv_cov_x, y_inv_cov_y') - 2 * xy_inv_cov; % Fix tiny negative values from floating-point error mahalanobis_sq(mahalanobis_sq < 0) = 0; % Step 4: Take square root to get final distances mahalanobis_dist = sqrt(mahalanobis_sq); % Verify with built-in function assert(all(all(abs(mahalanobis_dist - pdist2(X, Y, 'mahalanobis', cov_X)) < 1e-10)));
This approach avoids looping through each sample pair by leveraging matrix multiplication and bsxfun to broadcast the precomputed terms—making it much faster than iterative methods.
Why Your Initial Max Approach Failed
When you used max without specifying the dimension, Matlab computed the maximum value across the entire difference matrix instead of per sample pair. By adding the dimension argument (max(..., [], 2)), you tell Matlab to take the maximum along the feature axis, which gives the correct Chebyshev distance for each training-test pair.
内容的提问来源于stack exchange,提问作者amjay

