KDTreeSearcher
statistics: KDTreeSearcher
KD-tree nearest neighbor searcher
The KDTreeSearcher class implements a KD-tree search algorithm for
nearest neighbor queries. It stores training data and supports various
distance metrics along with their parameter values for performing a KD-tree
search. The KD-tree algorithm partitions the training data into a
hierarchical tree structure and performs search operations by traversing
the tree to reduce the number of distance computations. It facilitates
nearest neighbor queries using knnsearch and radius queries using
rangesearch.
You can either use the KDTreeSearcher class constructor or the
createns function to create an KDTreeSearcher object.
See also: createns, ExhaustiveSearcher, hnswSearcher, knnsearch, rangesearch
Source Code: KDTreeSearcher
The KDTreeSearcher class contains the following properties:
Point data, specified as an numeric matrix where each row is an observation and each column is a feature. This property is private and cannot be modified after object creation.
Data of class single is stored and searched in single
precision, any other numeric class is converted to double.
Demo to verify implementation using fisheriris dataset
load fisheriris numSamples = size (meas, 1); queryIndices = [1, 23, 46, 63, 109]; dataIndices = ! ismember (1:numSamples, queryIndices); queryPoints = meas(queryIndices, :); dataPoints = meas(dataIndices, :); searchRadius = 0.3; kdTree = KDTreeSearcher (dataPoints, 'Distance', 'minkowski')
kdTree =
KDTreeSearcher with properties:
BucketSize: 50
Distance: 'minkowski'
DistParameter: 2
X: [145x4 double]
nearestNeighbors = knnsearch (kdTree, queryPoints, 'K', 2)
nearestNeighbors =
17 4
6 2
1 12
89 66
124 100
neighborsInRange = rangesearch (kdTree, queryPoints, searchRadius)
neighborsInRange =
5x1 cell array
{[17 4 38 26 27 39 7 47 36]}
{1x0 double }
{[ 1 12 33 29 2 3 9]}
{1x0 double }
{1x0 double }
Create a KDTreeSearcher with Euclidean distance
X = [1, 2; 3, 4; 5, 6]; obj = KDTreeSearcher (X);
Find the nearest neighbor to [2, 3]
Y = [2, 3];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
1
disp ('Distance:');
Distance:
disp (D);
1.4142
Find all points within radius 2
[idx, D] = rangesearch (obj, Y, 2);
disp ('Indices within radius:');
Indices within radius:
disp (idx);
1x1 cell array
{[1 2]}
disp ('Distances:');
Distances:
disp (D);
1x1 cell array
{[1.41421 1.41421]}
Create a KDTreeSearcher with Minkowski distance (P=3)
X = [0, 0; 1, 0; 2, 0]; obj = KDTreeSearcher (X, 'Distance', 'minkowski', 'P', 3);
Find the nearest neighbor to [1, 0]
Y = [1, 0];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
2
disp ('Distance:');
Distance:
disp (D);
0
rng (42);
disp ('Demonstrating KDTreeSearcher');
Demonstrating KDTreeSearcher
n = 100;
mu1 = [0.3, 0.3];
mu2 = [0.7, 0.7];
sigma = 0.1;
X1 = mu1 + sigma * randn (n / 2, 2);
X2 = mu2 + sigma * randn (n / 2, 2);
X = [X1; X2];
obj = KDTreeSearcher (X);
Y = [0.3, 0.3; 0.7, 0.7; 0.5, 0.5];
K = 5;
[idx, D] = knnsearch (obj, Y, 'K', K);
disp ('For the first query point:');
For the first query point:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of nearest neighbors:');
Indices of nearest neighbors:
disp (idx(1,:));
49 19 14 46 34
disp ('Distances:');
Distances:
disp (D(1,:));
0.029932 0.040026 0.046845 0.051107 0.054789
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled'); # Training points
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled'); # Query points
for i = 1:size (Y, 1)
query = Y(i,:);
neighbors = X(idx(i,:), :);
for j = 1:K
plot ([query(1), neighbors(j,1)], [query(2), neighbors(j,2)], 'k-');
endfor
endfor
hold off;
title ('K Nearest Neighbors with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
r = 0.15;
[idx, D] = rangesearch (obj, Y, r);
disp ('For the first query point in rangesearch:');
For the first query point in rangesearch:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of points within radius:');
Indices of points within radius:
disp (idx{1});
Columns 1 through 22: 49 19 14 46 34 23 12 41 1 3 42 48 24 2 11 37 10 27 32 20 44 40 Columns 23 through 34: 39 21 7 31 45 30 4 16 47 9 29 8
disp ('Distances:');
Distances:
disp (D{1});
Columns 1 through 10: 0.029932 0.040026 0.046845 0.051107 0.054789 0.063517 0.067855 0.071365 0.073769 0.075991 Columns 11 through 20: 0.082686 0.084066 0.090008 0.095171 0.096337 0.096836 0.097593 0.098255 0.098948 0.101780 Columns 21 through 30: 0.108652 0.108983 0.114272 0.116760 0.120198 0.121721 0.122560 0.127342 0.128062 0.128687 Columns 31 through 34: 0.130208 0.136007 0.142870 0.143009
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled');
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled');
theta = linspace (0, 2 * pi, 100);
for i = 1:size (Y, 1)
center = Y(i,:);
x_circle = center(1) + r * cos (theta);
y_circle = center(2) + r * sin (theta);
plot (x_circle, y_circle, 'g-');
## Highlight points within radius
if (! isempty (idx{i}))
in_radius = X(idx{i}, :);
scatter (in_radius(:,1), in_radius(:,2), 36, 'g', 'filled');
endif
endfor
hold off
title ('Points within Radius with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
The maximum number of data points in the leaf node of the KD-tree. Default value is 50. This property is private and cannot be modified after object creation.
Demo to verify implementation using fisheriris dataset
load fisheriris numSamples = size (meas, 1); queryIndices = [1, 23, 46, 63, 109]; dataIndices = ! ismember (1:numSamples, queryIndices); queryPoints = meas(queryIndices, :); dataPoints = meas(dataIndices, :); searchRadius = 0.3; kdTree = KDTreeSearcher (dataPoints, 'Distance', 'minkowski')
kdTree =
KDTreeSearcher with properties:
BucketSize: 50
Distance: 'minkowski'
DistParameter: 2
X: [145x4 double]
nearestNeighbors = knnsearch (kdTree, queryPoints, 'K', 2)
nearestNeighbors =
17 4
6 2
1 12
89 66
124 100
neighborsInRange = rangesearch (kdTree, queryPoints, searchRadius)
neighborsInRange =
5x1 cell array
{[17 4 38 26 27 39 7 47 36]}
{1x0 double }
{[ 1 12 33 29 2 3 9]}
{1x0 double }
{1x0 double }
Create a KDTreeSearcher with Euclidean distance
X = [1, 2; 3, 4; 5, 6]; obj = KDTreeSearcher (X);
Find the nearest neighbor to [2, 3]
Y = [2, 3];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
1
disp ('Distance:');
Distance:
disp (D);
1.4142
Find all points within radius 2
[idx, D] = rangesearch (obj, Y, 2);
disp ('Indices within radius:');
Indices within radius:
disp (idx);
1x1 cell array
{[1 2]}
disp ('Distances:');
Distances:
disp (D);
1x1 cell array
{[1.41421 1.41421]}
Create a KDTreeSearcher with Minkowski distance (P=3)
X = [0, 0; 1, 0; 2, 0]; obj = KDTreeSearcher (X, 'Distance', 'minkowski', 'P', 3);
Find the nearest neighbor to [1, 0]
Y = [1, 0];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
2
disp ('Distance:');
Distance:
disp (D);
0
rng (42);
disp ('Demonstrating KDTreeSearcher');
Demonstrating KDTreeSearcher
n = 100;
mu1 = [0.3, 0.3];
mu2 = [0.7, 0.7];
sigma = 0.1;
X1 = mu1 + sigma * randn (n / 2, 2);
X2 = mu2 + sigma * randn (n / 2, 2);
X = [X1; X2];
obj = KDTreeSearcher (X);
Y = [0.3, 0.3; 0.7, 0.7; 0.5, 0.5];
K = 5;
[idx, D] = knnsearch (obj, Y, 'K', K);
disp ('For the first query point:');
For the first query point:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of nearest neighbors:');
Indices of nearest neighbors:
disp (idx(1,:));
49 19 14 46 34
disp ('Distances:');
Distances:
disp (D(1,:));
0.029932 0.040026 0.046845 0.051107 0.054789
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled'); # Training points
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled'); # Query points
for i = 1:size (Y, 1)
query = Y(i,:);
neighbors = X(idx(i,:), :);
for j = 1:K
plot ([query(1), neighbors(j,1)], [query(2), neighbors(j,2)], 'k-');
endfor
endfor
hold off;
title ('K Nearest Neighbors with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
r = 0.15;
[idx, D] = rangesearch (obj, Y, r);
disp ('For the first query point in rangesearch:');
For the first query point in rangesearch:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of points within radius:');
Indices of points within radius:
disp (idx{1});
Columns 1 through 22: 49 19 14 46 34 23 12 41 1 3 42 48 24 2 11 37 10 27 32 20 44 40 Columns 23 through 34: 39 21 7 31 45 30 4 16 47 9 29 8
disp ('Distances:');
Distances:
disp (D{1});
Columns 1 through 10: 0.029932 0.040026 0.046845 0.051107 0.054789 0.063517 0.067855 0.071365 0.073769 0.075991 Columns 11 through 20: 0.082686 0.084066 0.090008 0.095171 0.096337 0.096836 0.097593 0.098255 0.098948 0.101780 Columns 21 through 30: 0.108652 0.108983 0.114272 0.116760 0.120198 0.121721 0.122560 0.127342 0.128062 0.128687 Columns 31 through 34: 0.130208 0.136007 0.142870 0.143009
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled');
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled');
theta = linspace (0, 2 * pi, 100);
for i = 1:size (Y, 1)
center = Y(i,:);
x_circle = center(1) + r * cos (theta);
y_circle = center(2) + r * sin (theta);
plot (x_circle, y_circle, 'g-');
## Highlight points within radius
if (! isempty (idx{i}))
in_radius = X(idx{i}, :);
scatter (in_radius(:,1), in_radius(:,2), 36, 'g', 'filled');
endif
endfor
hold off
title ('Points within Radius with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
Distance metric used for searches, specified as a character vector.
Supported metrics are 'euclidean', 'cityblock',
'minkowski', and 'chebychev'. Default value is
'euclidean'.
Demo to verify implementation using fisheriris dataset
load fisheriris numSamples = size (meas, 1); queryIndices = [1, 23, 46, 63, 109]; dataIndices = ! ismember (1:numSamples, queryIndices); queryPoints = meas(queryIndices, :); dataPoints = meas(dataIndices, :); searchRadius = 0.3; kdTree = KDTreeSearcher (dataPoints, 'Distance', 'minkowski')
kdTree =
KDTreeSearcher with properties:
BucketSize: 50
Distance: 'minkowski'
DistParameter: 2
X: [145x4 double]
nearestNeighbors = knnsearch (kdTree, queryPoints, 'K', 2)
nearestNeighbors =
17 4
6 2
1 12
89 66
124 100
neighborsInRange = rangesearch (kdTree, queryPoints, searchRadius)
neighborsInRange =
5x1 cell array
{[17 4 38 26 27 39 7 47 36]}
{1x0 double }
{[ 1 12 33 29 2 3 9]}
{1x0 double }
{1x0 double }
Create a KDTreeSearcher with Euclidean distance
X = [1, 2; 3, 4; 5, 6]; obj = KDTreeSearcher (X);
Find the nearest neighbor to [2, 3]
Y = [2, 3];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
1
disp ('Distance:');
Distance:
disp (D);
1.4142
Find all points within radius 2
[idx, D] = rangesearch (obj, Y, 2);
disp ('Indices within radius:');
Indices within radius:
disp (idx);
1x1 cell array
{[1 2]}
disp ('Distances:');
Distances:
disp (D);
1x1 cell array
{[1.41421 1.41421]}
Create a KDTreeSearcher with Minkowski distance (P=3)
X = [0, 0; 1, 0; 2, 0]; obj = KDTreeSearcher (X, 'Distance', 'minkowski', 'P', 3);
Find the nearest neighbor to [1, 0]
Y = [1, 0];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
2
disp ('Distance:');
Distance:
disp (D);
0
rng (42);
disp ('Demonstrating KDTreeSearcher');
Demonstrating KDTreeSearcher
n = 100;
mu1 = [0.3, 0.3];
mu2 = [0.7, 0.7];
sigma = 0.1;
X1 = mu1 + sigma * randn (n / 2, 2);
X2 = mu2 + sigma * randn (n / 2, 2);
X = [X1; X2];
obj = KDTreeSearcher (X);
Y = [0.3, 0.3; 0.7, 0.7; 0.5, 0.5];
K = 5;
[idx, D] = knnsearch (obj, Y, 'K', K);
disp ('For the first query point:');
For the first query point:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of nearest neighbors:');
Indices of nearest neighbors:
disp (idx(1,:));
49 19 14 46 34
disp ('Distances:');
Distances:
disp (D(1,:));
0.029932 0.040026 0.046845 0.051107 0.054789
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled'); # Training points
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled'); # Query points
for i = 1:size (Y, 1)
query = Y(i,:);
neighbors = X(idx(i,:), :);
for j = 1:K
plot ([query(1), neighbors(j,1)], [query(2), neighbors(j,2)], 'k-');
endfor
endfor
hold off;
title ('K Nearest Neighbors with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
r = 0.15;
[idx, D] = rangesearch (obj, Y, r);
disp ('For the first query point in rangesearch:');
For the first query point in rangesearch:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of points within radius:');
Indices of points within radius:
disp (idx{1});
Columns 1 through 22: 49 19 14 46 34 23 12 41 1 3 42 48 24 2 11 37 10 27 32 20 44 40 Columns 23 through 34: 39 21 7 31 45 30 4 16 47 9 29 8
disp ('Distances:');
Distances:
disp (D{1});
Columns 1 through 10: 0.029932 0.040026 0.046845 0.051107 0.054789 0.063517 0.067855 0.071365 0.073769 0.075991 Columns 11 through 20: 0.082686 0.084066 0.090008 0.095171 0.096337 0.096836 0.097593 0.098255 0.098948 0.101780 Columns 21 through 30: 0.108652 0.108983 0.114272 0.116760 0.120198 0.121721 0.122560 0.127342 0.128062 0.128687 Columns 31 through 34: 0.130208 0.136007 0.142870 0.143009
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled');
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled');
theta = linspace (0, 2 * pi, 100);
for i = 1:size (Y, 1)
center = Y(i,:);
x_circle = center(1) + r * cos (theta);
y_circle = center(2) + r * sin (theta);
plot (x_circle, y_circle, 'g-');
## Highlight points within radius
if (! isempty (idx{i}))
in_radius = X(idx{i}, :);
scatter (in_radius(:,1), in_radius(:,2), 36, 'g', 'filled');
endif
endfor
hold off
title ('Points within Radius with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
The type and value of the distance parameter depends on the selected
Distance metric and can be any of the following:
'minkowski', a positive scalar exponent (default 2).
'euclidean', 'cityblock',
'chebychev'). Attempting to set a non-empty value for these
metrics will result in an error.
Demo to verify implementation using fisheriris dataset
load fisheriris numSamples = size (meas, 1); queryIndices = [1, 23, 46, 63, 109]; dataIndices = ! ismember (1:numSamples, queryIndices); queryPoints = meas(queryIndices, :); dataPoints = meas(dataIndices, :); searchRadius = 0.3; kdTree = KDTreeSearcher (dataPoints, 'Distance', 'minkowski')
kdTree =
KDTreeSearcher with properties:
BucketSize: 50
Distance: 'minkowski'
DistParameter: 2
X: [145x4 double]
nearestNeighbors = knnsearch (kdTree, queryPoints, 'K', 2)
nearestNeighbors =
17 4
6 2
1 12
89 66
124 100
neighborsInRange = rangesearch (kdTree, queryPoints, searchRadius)
neighborsInRange =
5x1 cell array
{[17 4 38 26 27 39 7 47 36]}
{1x0 double }
{[ 1 12 33 29 2 3 9]}
{1x0 double }
{1x0 double }
Create a KDTreeSearcher with Euclidean distance
X = [1, 2; 3, 4; 5, 6]; obj = KDTreeSearcher (X);
Find the nearest neighbor to [2, 3]
Y = [2, 3];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
1
disp ('Distance:');
Distance:
disp (D);
1.4142
Find all points within radius 2
[idx, D] = rangesearch (obj, Y, 2);
disp ('Indices within radius:');
Indices within radius:
disp (idx);
1x1 cell array
{[1 2]}
disp ('Distances:');
Distances:
disp (D);
1x1 cell array
{[1.41421 1.41421]}
Create a KDTreeSearcher with Minkowski distance (P=3)
X = [0, 0; 1, 0; 2, 0]; obj = KDTreeSearcher (X, 'Distance', 'minkowski', 'P', 3);
Find the nearest neighbor to [1, 0]
Y = [1, 0];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
2
disp ('Distance:');
Distance:
disp (D);
0
rng (42);
disp ('Demonstrating KDTreeSearcher');
Demonstrating KDTreeSearcher
n = 100;
mu1 = [0.3, 0.3];
mu2 = [0.7, 0.7];
sigma = 0.1;
X1 = mu1 + sigma * randn (n / 2, 2);
X2 = mu2 + sigma * randn (n / 2, 2);
X = [X1; X2];
obj = KDTreeSearcher (X);
Y = [0.3, 0.3; 0.7, 0.7; 0.5, 0.5];
K = 5;
[idx, D] = knnsearch (obj, Y, 'K', K);
disp ('For the first query point:');
For the first query point:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of nearest neighbors:');
Indices of nearest neighbors:
disp (idx(1,:));
49 19 14 46 34
disp ('Distances:');
Distances:
disp (D(1,:));
0.029932 0.040026 0.046845 0.051107 0.054789
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled'); # Training points
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled'); # Query points
for i = 1:size (Y, 1)
query = Y(i,:);
neighbors = X(idx(i,:), :);
for j = 1:K
plot ([query(1), neighbors(j,1)], [query(2), neighbors(j,2)], 'k-');
endfor
endfor
hold off;
title ('K Nearest Neighbors with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
r = 0.15;
[idx, D] = rangesearch (obj, Y, r);
disp ('For the first query point in rangesearch:');
For the first query point in rangesearch:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of points within radius:');
Indices of points within radius:
disp (idx{1});
Columns 1 through 22: 49 19 14 46 34 23 12 41 1 3 42 48 24 2 11 37 10 27 32 20 44 40 Columns 23 through 34: 39 21 7 31 45 30 4 16 47 9 29 8
disp ('Distances:');
Distances:
disp (D{1});
Columns 1 through 10: 0.029932 0.040026 0.046845 0.051107 0.054789 0.063517 0.067855 0.071365 0.073769 0.075991 Columns 11 through 20: 0.082686 0.084066 0.090008 0.095171 0.096337 0.096836 0.097593 0.098255 0.098948 0.101780 Columns 21 through 30: 0.108652 0.108983 0.114272 0.116760 0.120198 0.121721 0.122560 0.127342 0.128062 0.128687 Columns 31 through 34: 0.130208 0.136007 0.142870 0.143009
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled');
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled');
theta = linspace (0, 2 * pi, 100);
for i = 1:size (Y, 1)
center = Y(i,:);
x_circle = center(1) + r * cos (theta);
y_circle = center(2) + r * sin (theta);
plot (x_circle, y_circle, 'g-');
## Highlight points within radius
if (! isempty (idx{i}))
in_radius = X(idx{i}, :);
scatter (in_radius(:,1), in_radius(:,2), 36, 'g', 'filled');
endif
endfor
hold off
title ('Points within Radius with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
The KDTreeSearcher class offers the following public methods:
KDTreeSearcher: obj = KDTreeSearcher (X)
KDTreeSearcher: obj = KDTreeSearcher (X, name, value)
obj = KDTreeSearcher (X) constructs a
KDTreeSearcher object with training data X using the
default 'euclidean' distance metric. X must be an
numeric matrix, where rows represent observations and columns
represent features.
obj = KDTreeSearcher (X, name, value)
allows customization through name-value pairs:
| Name | Value |
|---|---|
'Distance' | Distance metric, specified as a
character vector ('euclidean', 'cityblock',
'minkowski', 'chebychev'). Default is
'euclidean'. |
'P' | Minkowski distance exponent, a positive
scalar. Valid only when 'Distance' is 'minkowski'.
Default is 2. |
'BucketSize' | Maximum number of data points in the leaf node of the KD-tree, a positive integer. Default is 50. |
You can also create a KDTreeSearcher object using the
createns function.
'Distance' and 'P' override the searcher’s own metric for
that call only; the Distance and DistParameter
properties keep their values. The tree is built from the data alone, so
changing the metric does not rebuild it. 'Cov' and
'Scale' are not accepted, since they belong to metrics a kd-tree
cannot search.
See also: KDTreeSearcher, knnsearch, rangesearch, createns
Demo to verify implementation using fisheriris dataset
load fisheriris numSamples = size (meas, 1); queryIndices = [1, 23, 46, 63, 109]; dataIndices = ! ismember (1:numSamples, queryIndices); queryPoints = meas(queryIndices, :); dataPoints = meas(dataIndices, :); searchRadius = 0.3; kdTree = KDTreeSearcher (dataPoints, 'Distance', 'minkowski')
kdTree =
KDTreeSearcher with properties:
BucketSize: 50
Distance: 'minkowski'
DistParameter: 2
X: [145x4 double]
nearestNeighbors = knnsearch (kdTree, queryPoints, 'K', 2)
nearestNeighbors =
17 4
6 2
1 12
89 66
124 100
neighborsInRange = rangesearch (kdTree, queryPoints, searchRadius)
neighborsInRange =
5x1 cell array
{[17 4 38 26 27 39 7 47 36]}
{1x0 double }
{[ 1 12 33 29 2 3 9]}
{1x0 double }
{1x0 double }
Create a KDTreeSearcher with Euclidean distance
X = [1, 2; 3, 4; 5, 6]; obj = KDTreeSearcher (X);
Find the nearest neighbor to [2, 3]
Y = [2, 3];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
1
disp ('Distance:');
Distance:
disp (D);
1.4142
Find all points within radius 2
[idx, D] = rangesearch (obj, Y, 2);
disp ('Indices within radius:');
Indices within radius:
disp (idx);
1x1 cell array
{[1 2]}
disp ('Distances:');
Distances:
disp (D);
1x1 cell array
{[1.41421 1.41421]}
Create a KDTreeSearcher with Minkowski distance (P=3)
X = [0, 0; 1, 0; 2, 0]; obj = KDTreeSearcher (X, 'Distance', 'minkowski', 'P', 3);
Find the nearest neighbor to [1, 0]
Y = [1, 0];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
2
disp ('Distance:');
Distance:
disp (D);
0
rng (42);
disp ('Demonstrating KDTreeSearcher');
Demonstrating KDTreeSearcher
n = 100;
mu1 = [0.3, 0.3];
mu2 = [0.7, 0.7];
sigma = 0.1;
X1 = mu1 + sigma * randn (n / 2, 2);
X2 = mu2 + sigma * randn (n / 2, 2);
X = [X1; X2];
obj = KDTreeSearcher (X);
Y = [0.3, 0.3; 0.7, 0.7; 0.5, 0.5];
K = 5;
[idx, D] = knnsearch (obj, Y, 'K', K);
disp ('For the first query point:');
For the first query point:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of nearest neighbors:');
Indices of nearest neighbors:
disp (idx(1,:));
49 19 14 46 34
disp ('Distances:');
Distances:
disp (D(1,:));
0.029932 0.040026 0.046845 0.051107 0.054789
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled'); # Training points
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled'); # Query points
for i = 1:size (Y, 1)
query = Y(i,:);
neighbors = X(idx(i,:), :);
for j = 1:K
plot ([query(1), neighbors(j,1)], [query(2), neighbors(j,2)], 'k-');
endfor
endfor
hold off;
title ('K Nearest Neighbors with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
r = 0.15;
[idx, D] = rangesearch (obj, Y, r);
disp ('For the first query point in rangesearch:');
For the first query point in rangesearch:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of points within radius:');
Indices of points within radius:
disp (idx{1});
Columns 1 through 22: 49 19 14 46 34 23 12 41 1 3 42 48 24 2 11 37 10 27 32 20 44 40 Columns 23 through 34: 39 21 7 31 45 30 4 16 47 9 29 8
disp ('Distances:');
Distances:
disp (D{1});
Columns 1 through 10: 0.029932 0.040026 0.046845 0.051107 0.054789 0.063517 0.067855 0.071365 0.073769 0.075991 Columns 11 through 20: 0.082686 0.084066 0.090008 0.095171 0.096337 0.096836 0.097593 0.098255 0.098948 0.101780 Columns 21 through 30: 0.108652 0.108983 0.114272 0.116760 0.120198 0.121721 0.122560 0.127342 0.128062 0.128687 Columns 31 through 34: 0.130208 0.136007 0.142870 0.143009
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled');
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled');
theta = linspace (0, 2 * pi, 100);
for i = 1:size (Y, 1)
center = Y(i,:);
x_circle = center(1) + r * cos (theta);
y_circle = center(2) + r * sin (theta);
plot (x_circle, y_circle, 'g-');
## Highlight points within radius
if (! isempty (idx{i}))
in_radius = X(idx{i}, :);
scatter (in_radius(:,1), in_radius(:,2), 36, 'g', 'filled');
endif
endfor
hold off
title ('Points within Radius with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
KDTreeSearcher: [idx, D] = knnsearch (obj, Y)
KDTreeSearcher: [idx, D] = knnsearch (obj, Y, name, value)
[idx, D] = knnsearch (obj, Y, K)
returns the indices idx and distances D of the
nearest neighbors in obj.X to each point in Y, using the
distance metric specified in obj.Distance.
KDTreeSearcher object.
idx is always of class double. D is of class
single when either obj.X or Y is single,
in which case the distances are computed in single precision, and of
class double otherwise.
[idx, D] = knnsearch (obj, Y, name,
value) allows additional options via name-value pairs:
| Name | Value |
|---|---|
'K' | A positive integer specifying the number of nearest neighbors to find. Default is 1. A value larger than the number of observations in the training data is answered with all of them, since there are no more neighbors to return. |
'IncludeTies' | Logical flag indicating whether to
include all neighbors tied with the th smallest distance. Default
is false. If true, idx and D are cell arrays. |
'SortIndices' | Logical flag indicating whether to
sort the indices by distance. Default is true. |
See also: KDTreeSearcher, rangesearch
Demo to verify implementation using fisheriris dataset
load fisheriris numSamples = size (meas, 1); queryIndices = [1, 23, 46, 63, 109]; dataIndices = ! ismember (1:numSamples, queryIndices); queryPoints = meas(queryIndices, :); dataPoints = meas(dataIndices, :); searchRadius = 0.3; kdTree = KDTreeSearcher (dataPoints, 'Distance', 'minkowski')
kdTree =
KDTreeSearcher with properties:
BucketSize: 50
Distance: 'minkowski'
DistParameter: 2
X: [145x4 double]
nearestNeighbors = knnsearch (kdTree, queryPoints, 'K', 2)
nearestNeighbors =
17 4
6 2
1 12
89 66
124 100
neighborsInRange = rangesearch (kdTree, queryPoints, searchRadius)
neighborsInRange =
5x1 cell array
{[17 4 38 26 27 39 7 47 36]}
{1x0 double }
{[ 1 12 33 29 2 3 9]}
{1x0 double }
{1x0 double }
Create a KDTreeSearcher with Euclidean distance
X = [1, 2; 3, 4; 5, 6]; obj = KDTreeSearcher (X);
Find the nearest neighbor to [2, 3]
Y = [2, 3];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
1
disp ('Distance:');
Distance:
disp (D);
1.4142
Find all points within radius 2
[idx, D] = rangesearch (obj, Y, 2);
disp ('Indices within radius:');
Indices within radius:
disp (idx);
1x1 cell array
{[1 2]}
disp ('Distances:');
Distances:
disp (D);
1x1 cell array
{[1.41421 1.41421]}
Create a KDTreeSearcher with Minkowski distance (P=3)
X = [0, 0; 1, 0; 2, 0]; obj = KDTreeSearcher (X, 'Distance', 'minkowski', 'P', 3);
Find the nearest neighbor to [1, 0]
Y = [1, 0];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
2
disp ('Distance:');
Distance:
disp (D);
0
rng (42);
disp ('Demonstrating KDTreeSearcher');
Demonstrating KDTreeSearcher
n = 100;
mu1 = [0.3, 0.3];
mu2 = [0.7, 0.7];
sigma = 0.1;
X1 = mu1 + sigma * randn (n / 2, 2);
X2 = mu2 + sigma * randn (n / 2, 2);
X = [X1; X2];
obj = KDTreeSearcher (X);
Y = [0.3, 0.3; 0.7, 0.7; 0.5, 0.5];
K = 5;
[idx, D] = knnsearch (obj, Y, 'K', K);
disp ('For the first query point:');
For the first query point:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of nearest neighbors:');
Indices of nearest neighbors:
disp (idx(1,:));
49 19 14 46 34
disp ('Distances:');
Distances:
disp (D(1,:));
0.029932 0.040026 0.046845 0.051107 0.054789
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled'); # Training points
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled'); # Query points
for i = 1:size (Y, 1)
query = Y(i,:);
neighbors = X(idx(i,:), :);
for j = 1:K
plot ([query(1), neighbors(j,1)], [query(2), neighbors(j,2)], 'k-');
endfor
endfor
hold off;
title ('K Nearest Neighbors with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
r = 0.15;
[idx, D] = rangesearch (obj, Y, r);
disp ('For the first query point in rangesearch:');
For the first query point in rangesearch:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of points within radius:');
Indices of points within radius:
disp (idx{1});
Columns 1 through 22: 49 19 14 46 34 23 12 41 1 3 42 48 24 2 11 37 10 27 32 20 44 40 Columns 23 through 34: 39 21 7 31 45 30 4 16 47 9 29 8
disp ('Distances:');
Distances:
disp (D{1});
Columns 1 through 10: 0.029932 0.040026 0.046845 0.051107 0.054789 0.063517 0.067855 0.071365 0.073769 0.075991 Columns 11 through 20: 0.082686 0.084066 0.090008 0.095171 0.096337 0.096836 0.097593 0.098255 0.098948 0.101780 Columns 21 through 30: 0.108652 0.108983 0.114272 0.116760 0.120198 0.121721 0.122560 0.127342 0.128062 0.128687 Columns 31 through 34: 0.130208 0.136007 0.142870 0.143009
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled');
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled');
theta = linspace (0, 2 * pi, 100);
for i = 1:size (Y, 1)
center = Y(i,:);
x_circle = center(1) + r * cos (theta);
y_circle = center(2) + r * sin (theta);
plot (x_circle, y_circle, 'g-');
## Highlight points within radius
if (! isempty (idx{i}))
in_radius = X(idx{i}, :);
scatter (in_radius(:,1), in_radius(:,2), 36, 'g', 'filled');
endif
endfor
hold off
title ('Points within Radius with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
KDTreeSearcher: [idx, D] = rangesearch (obj, Y, r)
KDTreeSearcher: [idx, D] = rangesearch (obj, Y, r, name, value)
[idx, D] = rangesearch (obj, Y, r)
returns the indices idx and distances D of all points in
obj.X within radius r of each point in Y, using the
distance metric specified in obj.Distance.
KDTreeSearcher object.
idx is always of class double. D is of class
single when either obj.X or Y is single,
in which case the distances are computed in single precision, and of
class double otherwise.
[idx, D] = rangesearch (obj, Y, r,
name,
value)
allows additional options via name-value pairs:
| Name | Value |
|---|---|
'SortIndices' | Logical flag indicating whether to
sort the indices by distance. Default is true. |
idx and D are cell arrays where each cell contains the indices and distances for one query point in Y.
See also: KDTreeSearcher, knnsearch
Demo to verify implementation using fisheriris dataset
load fisheriris numSamples = size (meas, 1); queryIndices = [1, 23, 46, 63, 109]; dataIndices = ! ismember (1:numSamples, queryIndices); queryPoints = meas(queryIndices, :); dataPoints = meas(dataIndices, :); searchRadius = 0.3; kdTree = KDTreeSearcher (dataPoints, 'Distance', 'minkowski')
kdTree =
KDTreeSearcher with properties:
BucketSize: 50
Distance: 'minkowski'
DistParameter: 2
X: [145x4 double]
nearestNeighbors = knnsearch (kdTree, queryPoints, 'K', 2)
nearestNeighbors =
17 4
6 2
1 12
89 66
124 100
neighborsInRange = rangesearch (kdTree, queryPoints, searchRadius)
neighborsInRange =
5x1 cell array
{[17 4 38 26 27 39 7 47 36]}
{1x0 double }
{[ 1 12 33 29 2 3 9]}
{1x0 double }
{1x0 double }
Create a KDTreeSearcher with Euclidean distance
X = [1, 2; 3, 4; 5, 6]; obj = KDTreeSearcher (X);
Find the nearest neighbor to [2, 3]
Y = [2, 3];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
1
disp ('Distance:');
Distance:
disp (D);
1.4142
Find all points within radius 2
[idx, D] = rangesearch (obj, Y, 2);
disp ('Indices within radius:');
Indices within radius:
disp (idx);
1x1 cell array
{[1 2]}
disp ('Distances:');
Distances:
disp (D);
1x1 cell array
{[1.41421 1.41421]}
Create a KDTreeSearcher with Minkowski distance (P=3)
X = [0, 0; 1, 0; 2, 0]; obj = KDTreeSearcher (X, 'Distance', 'minkowski', 'P', 3);
Find the nearest neighbor to [1, 0]
Y = [1, 0];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
2
disp ('Distance:');
Distance:
disp (D);
0
rng (42);
disp ('Demonstrating KDTreeSearcher');
Demonstrating KDTreeSearcher
n = 100;
mu1 = [0.3, 0.3];
mu2 = [0.7, 0.7];
sigma = 0.1;
X1 = mu1 + sigma * randn (n / 2, 2);
X2 = mu2 + sigma * randn (n / 2, 2);
X = [X1; X2];
obj = KDTreeSearcher (X);
Y = [0.3, 0.3; 0.7, 0.7; 0.5, 0.5];
K = 5;
[idx, D] = knnsearch (obj, Y, 'K', K);
disp ('For the first query point:');
For the first query point:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of nearest neighbors:');
Indices of nearest neighbors:
disp (idx(1,:));
49 19 14 46 34
disp ('Distances:');
Distances:
disp (D(1,:));
0.029932 0.040026 0.046845 0.051107 0.054789
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled'); # Training points
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled'); # Query points
for i = 1:size (Y, 1)
query = Y(i,:);
neighbors = X(idx(i,:), :);
for j = 1:K
plot ([query(1), neighbors(j,1)], [query(2), neighbors(j,2)], 'k-');
endfor
endfor
hold off;
title ('K Nearest Neighbors with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
r = 0.15;
[idx, D] = rangesearch (obj, Y, r);
disp ('For the first query point in rangesearch:');
For the first query point in rangesearch:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of points within radius:');
Indices of points within radius:
disp (idx{1});
Columns 1 through 22: 49 19 14 46 34 23 12 41 1 3 42 48 24 2 11 37 10 27 32 20 44 40 Columns 23 through 34: 39 21 7 31 45 30 4 16 47 9 29 8
disp ('Distances:');
Distances:
disp (D{1});
Columns 1 through 10: 0.029932 0.040026 0.046845 0.051107 0.054789 0.063517 0.067855 0.071365 0.073769 0.075991 Columns 11 through 20: 0.082686 0.084066 0.090008 0.095171 0.096337 0.096836 0.097593 0.098255 0.098948 0.101780 Columns 21 through 30: 0.108652 0.108983 0.114272 0.116760 0.120198 0.121721 0.122560 0.127342 0.128062 0.128687 Columns 31 through 34: 0.130208 0.136007 0.142870 0.143009
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled');
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled');
theta = linspace (0, 2 * pi, 100);
for i = 1:size (Y, 1)
center = Y(i,:);
x_circle = center(1) + r * cos (theta);
y_circle = center(2) + r * sin (theta);
plot (x_circle, y_circle, 'g-');
## Highlight points within radius
if (! isempty (idx{i}))
in_radius = X(idx{i}, :);
scatter (in_radius(:,1), in_radius(:,2), 36, 'g', 'filled');
endif
endfor
hold off
title ('Points within Radius with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
load fisheriris numSamples = size (meas, 1); queryIndices = [1, 23, 46, 63, 109]; dataIndices = ! ismember (1:numSamples, queryIndices); queryPoints = meas(queryIndices, :); dataPoints = meas(dataIndices, :); searchRadius = 0.3; kdTree = KDTreeSearcher (dataPoints, 'Distance', 'minkowski')
kdTree =
KDTreeSearcher with properties:
BucketSize: 50
Distance: 'minkowski'
DistParameter: 2
X: [145x4 double]
nearestNeighbors = knnsearch (kdTree, queryPoints, 'K', 2)
nearestNeighbors =
17 4
6 2
1 12
89 66
124 100
neighborsInRange = rangesearch (kdTree, queryPoints, searchRadius)
neighborsInRange =
5x1 cell array
{[17 4 38 26 27 39 7 47 36]}
{1x0 double }
{[ 1 12 33 29 2 3 9]}
{1x0 double }
{1x0 double }
X = [1, 2; 3, 4; 5, 6]; obj = KDTreeSearcher (X);
Find the nearest neighbor to [2, 3]
Y = [2, 3];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
1
disp ('Distance:');
Distance:
disp (D);
1.4142
Find all points within radius 2
[idx, D] = rangesearch (obj, Y, 2);
disp ('Indices within radius:');
Indices within radius:
disp (idx);
1x1 cell array
{[1 2]}
disp ('Distances:');
Distances:
disp (D);
1x1 cell array
{[1.41421 1.41421]}
X = [0, 0; 1, 0; 2, 0]; obj = KDTreeSearcher (X, 'Distance', 'minkowski', 'P', 3);
Find the nearest neighbor to [1, 0]
Y = [1, 0];
[idx, D] = knnsearch (obj, Y, 'K', 1);
disp ('Nearest neighbor index:');
Nearest neighbor index:
disp (idx);
2
disp ('Distance:');
Distance:
disp (D);
0
rng (42);
disp ('Demonstrating KDTreeSearcher');
Demonstrating KDTreeSearcher
n = 100;
mu1 = [0.3, 0.3];
mu2 = [0.7, 0.7];
sigma = 0.1;
X1 = mu1 + sigma * randn (n / 2, 2);
X2 = mu2 + sigma * randn (n / 2, 2);
X = [X1; X2];
obj = KDTreeSearcher (X);
Y = [0.3, 0.3; 0.7, 0.7; 0.5, 0.5];
K = 5;
[idx, D] = knnsearch (obj, Y, 'K', K);
disp ('For the first query point:');
For the first query point:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of nearest neighbors:');
Indices of nearest neighbors:
disp (idx(1,:));
49 19 14 46 34
disp ('Distances:');
Distances:
disp (D(1,:));
0.029932 0.040026 0.046845 0.051107 0.054789
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled'); # Training points
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled'); # Query points
for i = 1:size (Y, 1)
query = Y(i,:);
neighbors = X(idx(i,:), :);
for j = 1:K
plot ([query(1), neighbors(j,1)], [query(2), neighbors(j,2)], 'k-');
endfor
endfor
hold off;
title ('K Nearest Neighbors with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');
r = 0.15;
[idx, D] = rangesearch (obj, Y, r);
disp ('For the first query point in rangesearch:');
For the first query point in rangesearch:
disp (['Query point: ', num2str(Y(1,:))]);
Query point: 0.3 0.3
disp ('Indices of points within radius:');
Indices of points within radius:
disp (idx{1});
Columns 1 through 22: 49 19 14 46 34 23 12 41 1 3 42 48 24 2 11 37 10 27 32 20 44 40 Columns 23 through 34: 39 21 7 31 45 30 4 16 47 9 29 8
disp ('Distances:');
Distances:
disp (D{1});
Columns 1 through 10: 0.029932 0.040026 0.046845 0.051107 0.054789 0.063517 0.067855 0.071365 0.073769 0.075991 Columns 11 through 20: 0.082686 0.084066 0.090008 0.095171 0.096337 0.096836 0.097593 0.098255 0.098948 0.101780 Columns 21 through 30: 0.108652 0.108983 0.114272 0.116760 0.120198 0.121721 0.122560 0.127342 0.128062 0.128687 Columns 31 through 34: 0.130208 0.136007 0.142870 0.143009
figure;
scatter (X(:,1), X(:,2), 36, 'b', 'filled');
hold on;
scatter (Y(:,1), Y(:,2), 36, 'r', 'filled');
theta = linspace (0, 2 * pi, 100);
for i = 1:size (Y, 1)
center = Y(i,:);
x_circle = center(1) + r * cos (theta);
y_circle = center(2) + r * sin (theta);
plot (x_circle, y_circle, 'g-');
## Highlight points within radius
if (! isempty (idx{i}))
in_radius = X(idx{i}, :);
scatter (in_radius(:,1), in_radius(:,2), 36, 'g', 'filled');
endif
endfor
hold off
title ('Points within Radius with KDTreeSearcher');
xlabel ('X1');
ylabel ('X2');