-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcluster_estimates.m
More file actions
127 lines (104 loc) · 4.5 KB
/
Copy pathcluster_estimates.m
File metadata and controls
127 lines (104 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
function [winnerIdx, clusterLabels, xEstList] = cluster_estimates(xEstList, method, criterion)
% CLUSTER_ESTIMATES Cluster subset position estimates and select the winning cluster.
%
% [winnerIdx, clusterLabels, xEstList] = cluster_estimates(xEstList, method, criterion)
%
% INPUTS:
% xEstList [M x 2] position estimates, one per subset
% method string clustering method: 'ahc' | 'dbscan' | 'kmeans'
% (default: 'ahc')
% criterion string cluster selection criterion: 'largest' | 'minvar' | 'combined'
% (default: 'combined')
%
% OUTPUTS:
% winnerIdx integer label of the winning cluster
% clusterLabels [M x 1] integer cluster label for each estimate
% xEstList [M x 2] (returned unchanged; convenience pass-through)
%%
% CLUSTER SELECTION CRITERIA:
% 'largest' - pick the cluster with the most members
% 'minvar' - pick the cluster with the lowest intra-cluster variance
% 'combined' - from the top-3 largest clusters, pick the one with
% lowest intra-cluster position variance (singletons penalised)
if nargin < 2, method = 'ahc'; end
if nargin < 3, criterion = 'combined'; end
M = size(xEstList, 1);
% --- Step 1: Cluster ---
switch lower(method)
case 'ahc'
clusterLabels = cluster_ahc(xEstList);
case 'dbscan'
clusterLabels = cluster_dbscan(xEstList);
% Re-label noise points (-1) as singleton clusters so downstream
% code never sees -1 labels.
noiseIdx = find(clusterLabels == -1);
if ~isempty(noiseIdx)
maxLabel = max(clusterLabels(clusterLabels ~= -1));
if isempty(maxLabel), maxLabel = 0; end
for k = 1:numel(noiseIdx)
clusterLabels(noiseIdx(k)) = maxLabel + k;
end
end
case 'kmeans'
clusterLabels = cluster_kmeans(xEstList);
otherwise
error('cluster_estimates: unknown method ''%s''. Use ''ahc'', ''dbscan'', or ''kmeans''.', method);
end
% --- Step 2: Select winning cluster ---
winnerIdx = select_winner(xEstList, clusterLabels, criterion);
end
% =========================================================================
function labels = cluster_ahc(xEstList)
% Agglomerative hierarchical clustering with Ward linkage.
Z = linkage(xEstList, 'ward', 'euclidean');
labels = cluster(Z, 'cutoff', 0.6, 'criterion', 'distance');
end
% =========================================================================
function labels = cluster_dbscan(xEstList)
% DBSCAN clustering. Noise points labelled -1.
epsilon = 0.3;
minPts = 3;
labels = dbscan(xEstList, epsilon, minPts);
end
% =========================================================================
function labels = cluster_kmeans(xEstList)
% k-means with k=5 (or fewer if not enough points).
k = min(5, size(xEstList, 1));
labels = kmeans(xEstList, k, 'Replicates', 5);
end
% =========================================================================
function winnerIdx = select_winner(xEstList, clusterLabels, criterion)
uniqueLabels = unique(clusterLabels);
nClusters = numel(uniqueLabels);
clusterSizes = zeros(nClusters, 1);
clusterVars = zeros(nClusters, 1);
for c = 1:nClusters
lbl = uniqueLabels(c);
mask = (clusterLabels == lbl);
pts = xEstList(mask, :);
clusterSizes(c) = sum(mask);
if size(pts, 1) > 1
clusterVars(c) = mean(var(pts, 0, 1)); % mean variance over x and y
else
clusterVars(c) = Inf; % singleton: infinite variance penalty
end
end
switch lower(criterion)
case 'largest'
[~, bestC] = max(clusterSizes);
winnerIdx = uniqueLabels(bestC);
case 'minvar'
[~, bestC] = min(clusterVars);
winnerIdx = uniqueLabels(bestC);
case 'combined'
% From the top-3 largest clusters, pick the one with lowest variance
topN = min(3, nClusters);
[~, sortedBySizeDesc] = sort(clusterSizes, 'descend');
topIdx = sortedBySizeDesc(1:topN);
topVars = clusterVars(topIdx);
[~, best] = min(topVars);
winnerIdx = uniqueLabels(topIdx(best));
otherwise
error('select_winner: unknown criterion ''%s''. Use ''largest'', ''minvar'', or ''combined''.', criterion);
end
end