├── README.md ├── SCSL.m ├── datasets ├── MSRCV1_3v_Per0.1.mat ├── MSRCV1_3v_Per0.2.mat ├── MSRCV1_3v_Per0.3.mat ├── MSRCV1_3v_Per0.4.mat ├── MSRCV1_3v_Per0.5.mat ├── MSRCV1_3v_Per0.6.mat ├── MSRCV1_3v_Per0.7.mat ├── MSRCV1_3v_Per0.8.mat └── MSRCV1_3v_Per0.9.mat ├── functions ├── EProjSimplex_new.p ├── NormalizeData.m ├── OrthQP_solver.m ├── PCA1.m ├── SpectralClustering.m ├── constructA.m ├── eig1.m ├── findindex.m └── mySVD.m ├── measure ├── Clustering8Measure.m ├── Contingency.m ├── MutualInfo.m ├── RandIndex.m ├── bestMap.m ├── compute_f.m ├── compute_nmi.m └── myNMIACCwithmean.m └── run.m /README.md: -------------------------------------------------------------------------------- 1 | Code of AAAI 2024 "Sample-level Cross-view Similarity Learning for Incomplete Multi-view Clustering" 2 | 3 | Please run the 'run.m', and reproduce the results on 'MSRCV' datasets. 4 | 5 | Any problem can contact suyuanliu@nudt.edu.cn. Thanks. 6 | -------------------------------------------------------------------------------- /SCSL.m: -------------------------------------------------------------------------------- 1 | function [S,G,iter,obj] = SCSL(X,Y,beta,lambda,ind,index,ini) 2 | 3 | %% initialize 4 | maxIter = 50 ; % the number of iterations 5 | 6 | numclass = length(unique(Y)); 7 | k = numclass; 8 | numview = length(X); 9 | numsample = size(Y,1); 10 | 11 | missingindex = constructA(ind); 12 | 13 | %% Calculate Omega 14 | Omega = 0; 15 | for iv = 1:numview 16 | for jv = 1:numview 17 | Omega = Omega+ind(:,iv)*ind(:,jv)'; 18 | end 19 | end 20 | Omega = 1./Omega; 21 | clear ind_plus 22 | 23 | %% Initialize G with k-means 24 | eff_g = ind*ones(1,numview)'; 25 | eff_g = 1./eff_g; 26 | 27 | rng(12,'twister'); 28 | G = 0; 29 | 30 | if ini == 1 31 | for iv = 1:numview 32 | rng(12,'twister'); 33 | if size(X{iv},1)1) && (abs((obj(iter-1)-obj(iter))/(obj(iter-1)))<1e-3 || iter>maxIter || obj(iter) < 1e-10) 157 | flag = 0; 158 | end 159 | end 160 | -------------------------------------------------------------------------------- /datasets/MSRCV1_3v_Per0.1.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/datasets/MSRCV1_3v_Per0.1.mat -------------------------------------------------------------------------------- /datasets/MSRCV1_3v_Per0.2.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/datasets/MSRCV1_3v_Per0.2.mat -------------------------------------------------------------------------------- /datasets/MSRCV1_3v_Per0.3.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/datasets/MSRCV1_3v_Per0.3.mat -------------------------------------------------------------------------------- /datasets/MSRCV1_3v_Per0.4.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/datasets/MSRCV1_3v_Per0.4.mat -------------------------------------------------------------------------------- /datasets/MSRCV1_3v_Per0.5.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/datasets/MSRCV1_3v_Per0.5.mat -------------------------------------------------------------------------------- /datasets/MSRCV1_3v_Per0.6.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/datasets/MSRCV1_3v_Per0.6.mat -------------------------------------------------------------------------------- /datasets/MSRCV1_3v_Per0.7.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/datasets/MSRCV1_3v_Per0.7.mat -------------------------------------------------------------------------------- /datasets/MSRCV1_3v_Per0.8.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/datasets/MSRCV1_3v_Per0.8.mat -------------------------------------------------------------------------------- /datasets/MSRCV1_3v_Per0.9.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/datasets/MSRCV1_3v_Per0.9.mat -------------------------------------------------------------------------------- /functions/EProjSimplex_new.p: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/functions/EProjSimplex_new.p -------------------------------------------------------------------------------- /functions/NormalizeData.m: -------------------------------------------------------------------------------- 1 | function [ProcessData]=NormalizeData(X) 2 | 3 | [nFea,nSmp] = size(X); 4 | for i = 1:nSmp 5 | ProcessData(:,i) = X(:,i) ./ max(1e-12,norm(X(:,i))); 6 | end -------------------------------------------------------------------------------- /functions/OrthQP_solver.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/functions/OrthQP_solver.m -------------------------------------------------------------------------------- /functions/PCA1.m: -------------------------------------------------------------------------------- 1 | function [eigvector, eigvalue] = PCA1(data, options) 2 | %PCA Principal Component Analysis 3 | % 4 | % Usage: 5 | % [eigvector, eigvalue] = PCA(data, options) 6 | % [eigvector, eigvalue] = PCA(data) 7 | % 8 | % Input: 9 | % data - Data matrix. Each row vector of fea is a data point. 10 | % 11 | % options.ReducedDim - The dimensionality of the reduced subspace. If 0, 12 | % all the dimensions will be kept. 13 | % Default is 0. 14 | % 15 | % Output: 16 | % eigvector - Each column is an embedding function, for a new 17 | % data point (row vector) x, y = x*eigvector 18 | % will be the embedding result of x. 19 | % eigvalue - The sorted eigvalue of PCA eigen-problem. 20 | % 21 | % Examples: 22 | % fea = rand(7,10); 23 | % options=[]; 24 | % options.ReducedDim=4; 25 | % [eigvector,eigvalue] = PCA(fea,4); 26 | % Y = fea*eigvector; 27 | % 28 | % version 3.0 --Dec/2011 29 | % version 2.2 --Feb/2009 30 | % version 2.1 --June/2007 31 | % version 2.0 --May/2007 32 | % version 1.1 --Feb/2006 33 | % version 1.0 --April/2004 34 | % 35 | % Written by Deng Cai (dengcai AT gmail.com) 36 | % 37 | 38 | if (~exist('options','var')) 39 | options = []; 40 | end 41 | 42 | ReducedDim = 0; 43 | if isfield(options,'ReducedDim') 44 | ReducedDim = options.ReducedDim; 45 | end 46 | 47 | 48 | [nSmp,nFea] = size(data); 49 | if (ReducedDim > nFea) || (ReducedDim <=0) 50 | ReducedDim = nFea; 51 | end 52 | 53 | 54 | if issparse(data) 55 | data = full(data); 56 | end 57 | sampleMean = mean(data,1); 58 | data = (data - repmat(sampleMean,nSmp,1)); 59 | 60 | [eigvector, eigvalue] = mySVD(data',ReducedDim); 61 | eigvalue = full(diag(eigvalue)).^2; 62 | 63 | if isfield(options,'PCARatio') 64 | sumEig = sum(eigvalue); 65 | sumEig = sumEig*options.PCARatio; 66 | sumNow = 0; 67 | for idx = 1:length(eigvalue) 68 | sumNow = sumNow + eigvalue(idx); 69 | if sumNow >= sumEig 70 | break; 71 | end 72 | end 73 | eigvector = eigvector(:,1:idx); 74 | end 75 | 76 | -------------------------------------------------------------------------------- /functions/SpectralClustering.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % This function takes an adjacency matrix of a graph and computes the 3 | % clustering of the nodes using the spectral clustering algorithm of 4 | % Ng, Jordan and Weiss. 5 | % CMat: NxN adjacency matrix 6 | % n: number of groups for clustering 7 | % groups: N-dimensional vector containing the memberships of the N points 8 | % to the n groups obtained by spectral clustering 9 | %-------------------------------------------------------------------------- 10 | % Copyright @ Ehsan Elhamifar, 2012 11 | %-------------------------------------------------------------------------- 12 | 13 | function kerNS = SpectralClustering(CKSym,n) 14 | 15 | warning off; 16 | N = size(CKSym,1); 17 | MAXiter = 1000; % Maximum number of iterations for KMeans 18 | REPlic = 20; % Number of replications for KMeans 19 | 20 | % Normalized spectral clustering according to Ng & Jordan & Weiss 21 | % using Normalized Symmetric Laplacian L = I - D^{-1/2} W D^{-1/2} 22 | 23 | DN = diag( 1./sqrt(sum(CKSym)+eps) ); 24 | LapN = speye(N) - DN * CKSym * DN; 25 | [uN,sN,vN] = svd(LapN); 26 | kerN = vN(:,N-n+1:N); 27 | for i = 1:N 28 | kerNS(i,:) = kerN(i,:) ./ norm(kerN(i,:)+eps); 29 | end 30 | % groups = kmeans(kerNS,n,'maxiter',MAXiter,'replicates',REPlic,'EmptyAction','singleton'); 31 | 32 | % stream = RandStream.getGlobalStream; 33 | % reset(stream); 34 | % groups = litekmeans(kerNS,n, 'MaxIter',1000, 'Replicates',20); -------------------------------------------------------------------------------- /functions/constructA.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/functions/constructA.m -------------------------------------------------------------------------------- /functions/eig1.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tracesource/SCSL/64657c64cc1309029ebb92d059ccd091676090f1/functions/eig1.m -------------------------------------------------------------------------------- /functions/findindex.m: -------------------------------------------------------------------------------- 1 | function [X1, ind] = findindex(data, index) 2 | %FINDINDEX Summary of this function goes here 3 | % Detailed explanation goes here 4 | [numofview,~] = size(data); 5 | [~,numofsample] = size(data{1}); 6 | 7 | X1 = cell(numofview,1); 8 | 9 | ind = zeros(numofsample,numofview); 10 | for i=1:numofview 11 | [d,~]=size(data{i}); 12 | ind(index{i}, i) = 1; 13 | origin = data{i}; 14 | origin(isnan(origin)) = 0; 15 | X1{i} = NormalizeData(origin); 16 | end 17 | 18 | 19 | 20 | 21 | end 22 | 23 | -------------------------------------------------------------------------------- /functions/mySVD.m: -------------------------------------------------------------------------------- 1 | function [U, S, V] = mySVD(X,ReducedDim) 2 | %mySVD Accelerated singular value decomposition. 3 | % [U,S,V] = mySVD(X) produces a diagonal matrix S, of the 4 | % dimension as the rank of X and with nonnegative diagonal elements in 5 | % decreasing order, and unitary matrices U and V so that 6 | % X = U*S*V'. 7 | % 8 | % [U,S,V] = mySVD(X,ReducedDim) produces a diagonal matrix S, of the 9 | % dimension as ReducedDim and with nonnegative diagonal elements in 10 | % decreasing order, and unitary matrices U and V so that 11 | % Xhat = U*S*V' is the best approximation (with respect to F norm) of X 12 | % among all the matrices with rank no larger than ReducedDim. 13 | % 14 | % Based on the size of X, mySVD computes the eigvectors of X*X^T or X^T*X 15 | % first, and then convert them to the eigenvectors of the other. 16 | % 17 | % See also SVD. 18 | % 19 | % version 2.0 --Feb/2009 20 | % version 1.0 --April/2004 21 | % 22 | % Written by Deng Cai (dengcai AT gmail.com) 23 | % 24 | 25 | MAX_MATRIX_SIZE = 1600; % You can change this number according your machine computational power 26 | EIGVECTOR_RATIO = 0.1; % You can change this number according your machine computational power 27 | 28 | 29 | if ~exist('ReducedDim','var') 30 | ReducedDim = 0; 31 | end 32 | 33 | [nSmp, mFea] = size(X); 34 | if mFea/nSmp > 1.0713 35 | ddata = X*X'; 36 | ddata = max(ddata,ddata'); 37 | 38 | dimMatrix = size(ddata,1); 39 | if (ReducedDim > 0) && (dimMatrix > MAX_MATRIX_SIZE) && (ReducedDim < dimMatrix*EIGVECTOR_RATIO) 40 | option = struct('disp',0); 41 | [U, eigvalue] = eigs(ddata,ReducedDim,'la',option); 42 | eigvalue = diag(eigvalue); 43 | else 44 | if issparse(ddata) 45 | ddata = full(ddata); 46 | end 47 | 48 | [U, eigvalue] = eig(ddata); 49 | eigvalue = diag(eigvalue); 50 | [dump, index] = sort(-eigvalue); 51 | eigvalue = eigvalue(index); 52 | U = U(:, index); 53 | end 54 | clear ddata; 55 | 56 | maxEigValue = max(abs(eigvalue)); 57 | eigIdx = find(abs(eigvalue)/maxEigValue < 1e-10); 58 | eigvalue(eigIdx) = []; 59 | U(:,eigIdx) = []; 60 | 61 | if (ReducedDim > 0) && (ReducedDim < length(eigvalue)) 62 | eigvalue = eigvalue(1:ReducedDim); 63 | U = U(:,1:ReducedDim); 64 | end 65 | 66 | eigvalue_Half = eigvalue.^.5; 67 | S = spdiags(eigvalue_Half,0,length(eigvalue_Half),length(eigvalue_Half)); 68 | 69 | if nargout >= 3 70 | eigvalue_MinusHalf = eigvalue_Half.^-1; 71 | V = X'*(U.*repmat(eigvalue_MinusHalf',size(U,1),1)); 72 | end 73 | else 74 | ddata = X'*X; 75 | ddata = max(ddata,ddata'); 76 | 77 | dimMatrix = size(ddata,1); 78 | if (ReducedDim > 0) && (dimMatrix > MAX_MATRIX_SIZE) && (ReducedDim < dimMatrix*EIGVECTOR_RATIO) 79 | option = struct('disp',0); 80 | [V, eigvalue] = eigs(ddata,ReducedDim,'la',option); 81 | eigvalue = diag(eigvalue); 82 | else 83 | if issparse(ddata) 84 | ddata = full(ddata); 85 | end 86 | 87 | [V, eigvalue] = eig(ddata); 88 | eigvalue = diag(eigvalue); 89 | 90 | [dump, index] = sort(-eigvalue); 91 | eigvalue = eigvalue(index); 92 | V = V(:, index); 93 | end 94 | clear ddata; 95 | 96 | maxEigValue = max(abs(eigvalue)); 97 | eigIdx = find(abs(eigvalue)/maxEigValue < 1e-10); 98 | eigvalue(eigIdx) = []; 99 | V(:,eigIdx) = []; 100 | 101 | if (ReducedDim > 0) && (ReducedDim < length(eigvalue)) 102 | eigvalue = eigvalue(1:ReducedDim); 103 | V = V(:,1:ReducedDim); 104 | end 105 | 106 | eigvalue_Half = eigvalue.^.5; 107 | S = spdiags(eigvalue_Half,0,length(eigvalue_Half),length(eigvalue_Half)); 108 | 109 | eigvalue_MinusHalf = eigvalue_Half.^-1; 110 | U = X*(V.*repmat(eigvalue_MinusHalf',size(V,1),1)); 111 | end 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /measure/Clustering8Measure.m: -------------------------------------------------------------------------------- 1 | function result = Clustering8Measure(Y, predY) 2 | 3 | if size(Y,2) ~= 1 4 | Y = Y'; 5 | end; 6 | if size(predY,2) ~= 1 7 | predY = predY'; 8 | end; 9 | 10 | n = length(Y); 11 | 12 | uY = unique(Y); 13 | nclass = length(uY); 14 | Y0 = zeros(n,1); 15 | if nclass ~= max(Y) 16 | for i = 1:nclass 17 | Y0(find(Y == uY(i))) = i; 18 | end; 19 | Y = Y0; 20 | end; 21 | 22 | uY = unique(predY); 23 | nclass = length(uY); 24 | predY0 = zeros(n,1); 25 | if nclass ~= max(predY) 26 | for i = 1:nclass 27 | predY0(find(predY == uY(i))) = i; 28 | end; 29 | predY = predY0; 30 | end; 31 | 32 | 33 | Lidx = unique(Y); classnum = length(Lidx); 34 | predLidx = unique(predY); pred_classnum = length(predLidx); 35 | 36 | % purity 37 | correnum = 0; 38 | for ci = 1:pred_classnum 39 | incluster = Y(find(predY == predLidx(ci))); 40 | % cnub = unique(incluster); 41 | % inclunub = 0; 42 | % for cnubi = 1:length(cnub) 43 | % inclunub(cnubi) = length(find(incluster == cnub(cnubi))); 44 | % end; 45 | inclunub = hist(incluster, 1:max(incluster)); if isempty(inclunub) inclunub=0;end; 46 | correnum = correnum + max(inclunub); 47 | end; 48 | Purity = correnum/length(predY); 49 | 50 | %if pred_classnum 51 | res = bestMap(Y, predY); 52 | % accuarcy 53 | ACC = length(find(Y == res))/length(Y); 54 | % NMI 55 | MIhat = MutualInfo(Y,res); 56 | 57 | [Fscore Precision Recall] = compute_f(Y, predY); 58 | [nmi Entropy] = compute_nmi(Y, predY); 59 | AR=RandIndex(Y, predY); 60 | 61 | % result = [Fscore Precision Recall nmi AR Entropy ACC Purity]; 62 | %result = [Fscore Precision Recall nmi AR Entropy]; 63 | result = [ACC nmi Purity Fscore Precision Recall AR Entropy]; 64 | 65 | 66 | 67 | %% 68 | function [newL2, c] = bestMap(L1,L2) 69 | %bestmap: permute labels of L2 match L1 as good as possible 70 | % [newL2] = bestMap(L1,L2); 71 | 72 | %=========== 73 | L1 = L1(:); 74 | L2 = L2(:); 75 | if size(L1) ~= size(L2) 76 | error('size(L1) must == size(L2)'); 77 | end 78 | L1 = L1 - min(L1) + 1; % min (L1) <- 1; 79 | L2 = L2 - min(L2) + 1; % min (L2) <- 1; 80 | %=========== make bipartition graph ============ 81 | nClass = max(max(L1), max(L2)); 82 | G = zeros(nClass); 83 | for i=1:nClass 84 | for j=1:nClass 85 | G(i,j) = length(find(L1 == i & L2 == j)); 86 | end 87 | end 88 | %=========== assign with hungarian method ====== 89 | [c,t] = hungarian(-G); 90 | newL2 = zeros(nClass,1); 91 | for i=1:nClass 92 | newL2(L2 == i) = c(i); 93 | end 94 | 95 | 96 | 97 | 98 | 99 | %% 100 | function MIhat = MutualInfo(L1,L2) 101 | % mutual information 102 | 103 | %=========== 104 | L1 = L1(:); 105 | L2 = L2(:); 106 | if size(L1) ~= size(L2) 107 | error('size(L1) must == size(L2)'); 108 | end 109 | L1 = L1 - min(L1) + 1; % min (L1) <- 1; 110 | L2 = L2 - min(L2) + 1; % min (L2) <- 1; 111 | %=========== make bipartition graph ============ 112 | nClass = max(max(L1), max(L2)); 113 | G = zeros(nClass); 114 | for i=1:nClass 115 | for j=1:nClass 116 | G(i,j) = length(find(L1 == i & L2 == j))+eps; 117 | end 118 | end 119 | sumG = sum(G(:)); 120 | %=========== calculate MIhat 121 | P1 = sum(G,2); P1 = P1/sumG; 122 | P2 = sum(G,1); P2 = P2/sumG; 123 | H1 = sum(-P1.*log2(P1)); 124 | H2 = sum(-P2.*log2(P2)); 125 | P12 = G/sumG; 126 | PPP = P12./repmat(P2,nClass,1)./repmat(P1,1,nClass); 127 | PPP(abs(PPP) < 1e-12) = 1; 128 | MI = sum(P12(:) .* log2(PPP(:))); 129 | MIhat = MI / max(H1,H2); 130 | %%%%%%%%%%%%% why complex ? %%%%%%%% 131 | MIhat = real(MIhat); 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | %% 141 | function [C,T]=hungarian(A) 142 | %HUNGARIAN Solve the Assignment problem using the Hungarian method. 143 | % 144 | %[C,T]=hungarian(A) 145 | %A - a square cost matrix. 146 | %C - the optimal assignment. 147 | %T - the cost of the optimal assignment. 148 | %s.t. T = trace(A(C,:)) is minimized over all possible assignments. 149 | 150 | % Adapted from the FORTRAN IV code in Carpaneto and Toth, "Algorithm 548: 151 | % Solution of the assignment problem [H]", ACM Transactions on 152 | % Mathematical Software, 6(1):104-111, 1980. 153 | 154 | % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se. 155 | % Department of Computing Science, Ume?University, 156 | % Sweden. 157 | % All standard disclaimers apply. 158 | 159 | % A substantial effort was put into this code. If you use it for a 160 | % publication or otherwise, please include an acknowledgement or at least 161 | % notify me by email. /Niclas 162 | 163 | [m,n]=size(A); 164 | 165 | if (m~=n) 166 | error('HUNGARIAN: Cost matrix must be square!'); 167 | end 168 | 169 | % Save original cost matrix. 170 | orig=A; 171 | 172 | % Reduce matrix. 173 | A=hminired(A); 174 | 175 | % Do an initial assignment. 176 | [A,C,U]=hminiass(A); 177 | 178 | % Repeat while we have unassigned rows. 179 | while (U(n+1)) 180 | % Start with no path, no unchecked zeros, and no unexplored rows. 181 | LR=zeros(1,n); 182 | LC=zeros(1,n); 183 | CH=zeros(1,n); 184 | RH=[zeros(1,n) -1]; 185 | 186 | % No labelled columns. 187 | SLC=[]; 188 | 189 | % Start path in first unassigned row. 190 | r=U(n+1); 191 | % Mark row with end-of-path label. 192 | LR(r)=-1; 193 | % Insert row first in labelled row set. 194 | SLR=r; 195 | 196 | % Repeat until we manage to find an assignable zero. 197 | while (1) 198 | % If there are free zeros in row r 199 | if (A(r,n+1)~=0) 200 | % ...get column of first free zero. 201 | l=-A(r,n+1); 202 | 203 | % If there are more free zeros in row r and row r in not 204 | % yet marked as unexplored.. 205 | if (A(r,l)~=0 & RH(r)==0) 206 | % Insert row r first in unexplored list. 207 | RH(r)=RH(n+1); 208 | RH(n+1)=r; 209 | 210 | % Mark in which column the next unexplored zero in this row 211 | % is. 212 | CH(r)=-A(r,l); 213 | end 214 | else 215 | % If all rows are explored.. 216 | if (RH(n+1)<=0) 217 | % Reduce matrix. 218 | [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR); 219 | end 220 | 221 | % Re-start with first unexplored row. 222 | r=RH(n+1); 223 | % Get column of next free zero in row r. 224 | l=CH(r); 225 | % Advance "column of next free zero". 226 | CH(r)=-A(r,l); 227 | % If this zero is last in the list.. 228 | if (A(r,l)==0) 229 | % ...remove row r from unexplored list. 230 | RH(n+1)=RH(r); 231 | RH(r)=0; 232 | end 233 | end 234 | 235 | % While the column l is labelled, i.e. in path. 236 | while (LC(l)~=0) 237 | % If row r is explored.. 238 | if (RH(r)==0) 239 | % If all rows are explored.. 240 | if (RH(n+1)<=0) 241 | % Reduce cost matrix. 242 | [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR); 243 | end 244 | 245 | % Re-start with first unexplored row. 246 | r=RH(n+1); 247 | end 248 | 249 | % Get column of next free zero in row r. 250 | l=CH(r); 251 | 252 | % Advance "column of next free zero". 253 | CH(r)=-A(r,l); 254 | 255 | % If this zero is last in list.. 256 | if(A(r,l)==0) 257 | % ...remove row r from unexplored list. 258 | RH(n+1)=RH(r); 259 | RH(r)=0; 260 | end 261 | end 262 | 263 | % If the column found is unassigned.. 264 | if (C(l)==0) 265 | % Flip all zeros along the path in LR,LC. 266 | [A,C,U]=hmflip(A,C,LC,LR,U,l,r); 267 | % ...and exit to continue with next unassigned row. 268 | break; 269 | else 270 | % ...else add zero to path. 271 | 272 | % Label column l with row r. 273 | LC(l)=r; 274 | 275 | % Add l to the set of labelled columns. 276 | SLC=[SLC l]; 277 | 278 | % Continue with the row assigned to column l. 279 | r=C(l); 280 | 281 | % Label row r with column l. 282 | LR(r)=l; 283 | 284 | % Add r to the set of labelled rows. 285 | SLR=[SLR r]; 286 | end 287 | end 288 | end 289 | 290 | % Calculate the total cost. 291 | T=sum(orig(logical(sparse(C,1:size(orig,2),1)))); 292 | 293 | 294 | function A=hminired(A) 295 | %HMINIRED Initial reduction of cost matrix for the Hungarian method. 296 | % 297 | %B=assredin(A) 298 | %A - the unreduced cost matris. 299 | %B - the reduced cost matrix with linked zeros in each row. 300 | 301 | % v1.0 96-06-13. Niclas Borlin, niclas@cs.umu.se. 302 | 303 | [m,n]=size(A); 304 | 305 | % Subtract column-minimum values from each column. 306 | colMin=min(A); 307 | A=A-colMin(ones(n,1),:); 308 | 309 | % Subtract row-minimum values from each row. 310 | rowMin=min(A')'; 311 | A=A-rowMin(:,ones(1,n)); 312 | 313 | % Get positions of all zeros. 314 | [i,j]=find(A==0); 315 | 316 | % Extend A to give room for row zero list header column. 317 | A(1,n+1)=0; 318 | for k=1:n 319 | % Get all column in this row. 320 | cols=j(k==i)'; 321 | % Insert pointers in matrix. 322 | A(k,[n+1 cols])=[-cols 0]; 323 | end 324 | 325 | 326 | function [A,C,U]=hminiass(A) 327 | %HMINIASS Initial assignment of the Hungarian method. 328 | % 329 | %[B,C,U]=hminiass(A) 330 | %A - the reduced cost matrix. 331 | %B - the reduced cost matrix, with assigned zeros removed from lists. 332 | %C - a vector. C(J)=I means row I is assigned to column J, 333 | % i.e. there is an assigned zero in position I,J. 334 | %U - a vector with a linked list of unassigned rows. 335 | 336 | % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se. 337 | 338 | [n,np1]=size(A); 339 | 340 | % Initalize return vectors. 341 | C=zeros(1,n); 342 | U=zeros(1,n+1); 343 | 344 | % Initialize last/next zero "pointers". 345 | LZ=zeros(1,n); 346 | NZ=zeros(1,n); 347 | 348 | for i=1:n 349 | % Set j to first unassigned zero in row i. 350 | lj=n+1; 351 | j=-A(i,lj); 352 | 353 | % Repeat until we have no more zeros (j==0) or we find a zero 354 | % in an unassigned column (c(j)==0). 355 | 356 | while (C(j)~=0) 357 | % Advance lj and j in zero list. 358 | lj=j; 359 | j=-A(i,lj); 360 | 361 | % Stop if we hit end of list. 362 | if (j==0) 363 | break; 364 | end 365 | end 366 | 367 | if (j~=0) 368 | % We found a zero in an unassigned column. 369 | 370 | % Assign row i to column j. 371 | C(j)=i; 372 | 373 | % Remove A(i,j) from unassigned zero list. 374 | A(i,lj)=A(i,j); 375 | 376 | % Update next/last unassigned zero pointers. 377 | NZ(i)=-A(i,j); 378 | LZ(i)=lj; 379 | 380 | % Indicate A(i,j) is an assigned zero. 381 | A(i,j)=0; 382 | else 383 | % We found no zero in an unassigned column. 384 | 385 | % Check all zeros in this row. 386 | 387 | lj=n+1; 388 | j=-A(i,lj); 389 | 390 | % Check all zeros in this row for a suitable zero in another row. 391 | while (j~=0) 392 | % Check the in the row assigned to this column. 393 | r=C(j); 394 | 395 | % Pick up last/next pointers. 396 | lm=LZ(r); 397 | m=NZ(r); 398 | 399 | % Check all unchecked zeros in free list of this row. 400 | while (m~=0) 401 | % Stop if we find an unassigned column. 402 | if (C(m)==0) 403 | break; 404 | end 405 | 406 | % Advance one step in list. 407 | lm=m; 408 | m=-A(r,lm); 409 | end 410 | 411 | if (m==0) 412 | % We failed on row r. Continue with next zero on row i. 413 | lj=j; 414 | j=-A(i,lj); 415 | else 416 | % We found a zero in an unassigned column. 417 | 418 | % Replace zero at (r,m) in unassigned list with zero at (r,j) 419 | A(r,lm)=-j; 420 | A(r,j)=A(r,m); 421 | 422 | % Update last/next pointers in row r. 423 | NZ(r)=-A(r,m); 424 | LZ(r)=j; 425 | 426 | % Mark A(r,m) as an assigned zero in the matrix . . . 427 | A(r,m)=0; 428 | 429 | % ...and in the assignment vector. 430 | C(m)=r; 431 | 432 | % Remove A(i,j) from unassigned list. 433 | A(i,lj)=A(i,j); 434 | 435 | % Update last/next pointers in row r. 436 | NZ(i)=-A(i,j); 437 | LZ(i)=lj; 438 | 439 | % Mark A(r,m) as an assigned zero in the matrix . . . 440 | A(i,j)=0; 441 | 442 | % ...and in the assignment vector. 443 | C(j)=i; 444 | 445 | % Stop search. 446 | break; 447 | end 448 | end 449 | end 450 | end 451 | 452 | % Create vector with list of unassigned rows. 453 | 454 | % Mark all rows have assignment. 455 | r=zeros(1,n); 456 | rows=C(C~=0); 457 | r(rows)=rows; 458 | empty=find(r==0); 459 | 460 | % Create vector with linked list of unassigned rows. 461 | U=zeros(1,n+1); 462 | U([n+1 empty])=[empty 0]; 463 | 464 | 465 | function [A,C,U]=hmflip(A,C,LC,LR,U,l,r) 466 | %HMFLIP Flip assignment state of all zeros along a path. 467 | % 468 | %[A,C,U]=hmflip(A,C,LC,LR,U,l,r) 469 | %Input: 470 | %A - the cost matrix. 471 | %C - the assignment vector. 472 | %LC - the column label vector. 473 | %LR - the row label vector. 474 | %U - the 475 | %r,l - position of last zero in path. 476 | %Output: 477 | %A - updated cost matrix. 478 | %C - updated assignment vector. 479 | %U - updated unassigned row list vector. 480 | 481 | % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se. 482 | 483 | n=size(A,1); 484 | 485 | while (1) 486 | % Move assignment in column l to row r. 487 | C(l)=r; 488 | 489 | % Find zero to be removed from zero list.. 490 | 491 | % Find zero before this. 492 | m=find(A(r,:)==-l); 493 | 494 | % Link past this zero. 495 | A(r,m)=A(r,l); 496 | 497 | A(r,l)=0; 498 | 499 | % If this was the first zero of the path.. 500 | if (LR(r)<0) 501 | ...remove row from unassigned row list and return. 502 | U(n+1)=U(r); 503 | U(r)=0; 504 | return; 505 | else 506 | 507 | % Move back in this row along the path and get column of next zero. 508 | l=LR(r); 509 | 510 | % Insert zero at (r,l) first in zero list. 511 | A(r,l)=A(r,n+1); 512 | A(r,n+1)=-l; 513 | 514 | % Continue back along the column to get row of next zero in path. 515 | r=LC(l); 516 | end 517 | end 518 | 519 | 520 | function [A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR) 521 | %HMREDUCE Reduce parts of cost matrix in the Hungerian method. 522 | % 523 | %[A,CH,RH]=hmreduce(A,CH,RH,LC,LR,SLC,SLR) 524 | %Input: 525 | %A - Cost matrix. 526 | %CH - vector of column of 'next zeros' in each row. 527 | %RH - vector with list of unexplored rows. 528 | %LC - column labels. 529 | %RC - row labels. 530 | %SLC - set of column labels. 531 | %SLR - set of row labels. 532 | % 533 | %Output: 534 | %A - Reduced cost matrix. 535 | %CH - Updated vector of 'next zeros' in each row. 536 | %RH - Updated vector of unexplored rows. 537 | 538 | % v1.0 96-06-14. Niclas Borlin, niclas@cs.umu.se. 539 | 540 | n=size(A,1); 541 | 542 | % Find which rows are covered, i.e. unlabelled. 543 | coveredRows=LR==0; 544 | 545 | % Find which columns are covered, i.e. labelled. 546 | coveredCols=LC~=0; 547 | 548 | r=find(~coveredRows); 549 | c=find(~coveredCols); 550 | 551 | % Get minimum of uncovered elements. 552 | m=min(min(A(r,c))); 553 | 554 | % Subtract minimum from all uncovered elements. 555 | A(r,c)=A(r,c)-m; 556 | 557 | % Check all uncovered columns.. 558 | for j=c 559 | % ...and uncovered rows in path order.. 560 | for i=SLR 561 | % If this is a (new) zero.. 562 | if (A(i,j)==0) 563 | % If the row is not in unexplored list.. 564 | if (RH(i)==0) 565 | % ...insert it first in unexplored list. 566 | RH(i)=RH(n+1); 567 | RH(n+1)=i; 568 | % Mark this zero as "next free" in this row. 569 | CH(i)=j; 570 | end 571 | % Find last unassigned zero on row I. 572 | row=A(i,:); 573 | colsInList=-row(row<0); 574 | if (length(colsInList)==0) 575 | % No zeros in the list. 576 | l=n+1; 577 | else 578 | l=colsInList(row(colsInList)==0); 579 | end 580 | % Append this zero to end of list. 581 | A(i,l)=-j; 582 | end 583 | end 584 | end 585 | 586 | % Add minimum to all doubly covered elements. 587 | r=find(coveredRows); 588 | c=find(coveredCols); 589 | 590 | % Take care of the zeros we will remove. 591 | [i,j]=find(A(r,c)<=0); 592 | 593 | i=r(i); 594 | j=c(j); 595 | 596 | for k=1:length(i) 597 | % Find zero before this in this row. 598 | lj=find(A(i(k),:)==-j(k)); 599 | % Link past it. 600 | A(i(k),lj)=A(i(k),j(k)); 601 | % Mark it as assigned. 602 | A(i(k),j(k))=0; 603 | end 604 | 605 | A(r,c)=A(r,c)+m; 606 | -------------------------------------------------------------------------------- /measure/Contingency.m: -------------------------------------------------------------------------------- 1 | function Cont=Contingency(Mem1,Mem2) 2 | %CONTINGENCY Form contigency matrix for two vectors 3 | % C=Contingency(Mem1,Mem2) returns contingency matrix for two 4 | % column vectors Mem1, Mem2. These define which cluster each entity 5 | % has been assigned to. 6 | % 7 | % See also RANDINDEX. 8 | % 9 | 10 | %(C) David Corney (2000) D.Corney@cs.ucl.ac.uk 11 | 12 | if nargin < 2 | min(size(Mem1)) > 1 | min(size(Mem2)) > 1 13 | error('Contingency: Requires two vector arguments') 14 | return 15 | end 16 | 17 | Cont=zeros(max(Mem1),max(Mem2)); 18 | 19 | for i = 1:length(Mem1); 20 | Cont(Mem1(i),Mem2(i))=Cont(Mem1(i),Mem2(i))+1; 21 | end 22 | -------------------------------------------------------------------------------- /measure/MutualInfo.m: -------------------------------------------------------------------------------- 1 | function MIhat = MutualInfo(L1,L2) 2 | % mutual information 3 | %=========== 4 | L1 = L1(:); 5 | L2 = L2(:); 6 | if size(L1) ~= size(L2) 7 | error('size(L1) must == size(L2)'); 8 | end 9 | 10 | Label = unique(L1); 11 | nClass = length(Label); 12 | 13 | Label2 = unique(L2); 14 | nClass2 = length(Label2); 15 | if nClass2 < nClass 16 | % smooth 17 | L1 = [L1; Label]; 18 | L2 = [L2; Label]; 19 | elseif nClass2 > nClass 20 | % smooth 21 | L1 = [L1; Label2]; 22 | L2 = [L2; Label2]; 23 | end 24 | 25 | 26 | G = zeros(nClass); 27 | for i=1:nClass 28 | for j=1:nClass 29 | G(i,j) = sum(L1 == Label(i) & L2 == Label(j)); 30 | end 31 | end 32 | sumG = sum(G(:)); 33 | 34 | P1 = sum(G,2); P1 = P1/sumG; 35 | P2 = sum(G,1); P2 = P2/sumG; 36 | if sum(P1==0) > 0 || sum(P2==0) > 0 37 | % smooth 38 | error('Smooth fail!'); 39 | else 40 | H1 = sum(-P1.*log2(P1)); 41 | H2 = sum(-P2.*log2(P2)); 42 | P12 = G/sumG; 43 | PPP = P12./repmat(P2,nClass,1)./repmat(P1,1,nClass); 44 | PPP(abs(PPP) < 1e-12) = 1; 45 | MI = sum(P12(:) .* log2(PPP(:))); 46 | MIhat = MI / max(H1,H2); 47 | %%%%%%%%%%%%% why complex ? %%%%%%%% 48 | MIhat = real(MIhat); 49 | end 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /measure/RandIndex.m: -------------------------------------------------------------------------------- 1 | function [AR,RI,MI,HI]=RandIndex(c1,c2) 2 | %RANDINDEX - calculates Rand Indices to compare two partitions 3 | % ARI=RANDINDEX(c1,c2), where c1,c2 are vectors listing the 4 | % class membership, returns the "Hubert & Arabie adjusted Rand index". 5 | % [AR,RI,MI,HI]=RANDINDEX(c1,c2) returns the adjusted Rand index, 6 | % the unadjusted Rand index, "Mirkin's" index and "Hubert's" index. 7 | % 8 | % See L. Hubert and P. Arabie (1985) "Comparing Partitions" Journal of 9 | % Classification 2:193-218 10 | 11 | %(C) David Corney (2000) D.Corney@cs.ucl.ac.uk 12 | 13 | if nargin < 2 | min(size(c1)) > 1 | min(size(c2)) > 1 14 | error('RandIndex: Requires two vector arguments') 15 | return 16 | end 17 | 18 | C=Contingency(c1,c2); %form contingency matrix 19 | 20 | n=sum(sum(C)); 21 | nis=sum(sum(C,2).^2); %sum of squares of sums of rows 22 | njs=sum(sum(C,1).^2); %sum of squares of sums of columns 23 | 24 | t1=nchoosek(n,2); %total number of pairs of entities 25 | t2=sum(sum(C.^2)); %sum over rows & columnns of nij^2 26 | t3=.5*(nis+njs); 27 | 28 | %Expected index (for adjustment) 29 | nc=(n*(n^2+1)-(n+1)*nis-(n+1)*njs+2*(nis*njs)/n)/(2*(n-1)); 30 | 31 | A=t1+t2-t3; %no. agreements 32 | D= -t2+t3; %no. disagreements 33 | 34 | if t1==nc 35 | AR=0; %avoid division by zero; if k=1, define Rand = 0 36 | else 37 | AR=(A-nc)/(t1-nc); %adjusted Rand - Hubert & Arabie 1985 38 | end 39 | 40 | RI=A/t1; %Rand 1971 %Probability of agreement 41 | MI=D/t1; %Mirkin 1970 %p(disagreement) 42 | HI=(A-D)/t1; %Hubert 1977 %p(agree)-p(disagree) 43 | 44 | -------------------------------------------------------------------------------- /measure/bestMap.m: -------------------------------------------------------------------------------- 1 | function [newL2] = bestMap(L1,L2) 2 | %bestmap: permute labels of L2 to match L1 as good as possible 3 | % [newL2] = bestMap(L1,L2); 4 | % 5 | % version 2.0 --May/2007 6 | % version 1.0 --November/2003 7 | % 8 | % Written by Deng Cai (dengcai AT gmail.com) 9 | 10 | 11 | %=========== 12 | 13 | L1 = L1(:); 14 | L2 = L2(:); 15 | if size(L1) ~= size(L2) 16 | error('size(L1) must == size(L2)'); 17 | end 18 | 19 | Label1 = unique(L1); 20 | nClass1 = length(Label1); 21 | Label2 = unique(L2); 22 | nClass2 = length(Label2); 23 | 24 | nClass = max(nClass1,nClass2); 25 | G = zeros(nClass); 26 | for i=1:nClass1 27 | for j=1:nClass2 28 | G(i,j) = length(find(L1 == Label1(i) & L2 == Label2(j))); 29 | end 30 | end 31 | 32 | [c,t] = hungarian(-G); 33 | newL2 = zeros(size(L2)); 34 | for i=1:nClass2 35 | newL2(L2 == Label2(i)) = Label1(c(i)); 36 | end 37 | -------------------------------------------------------------------------------- /measure/compute_f.m: -------------------------------------------------------------------------------- 1 | function [f,p,r] = compute_f(T,H) 2 | 3 | if length(T) ~= length(H), 4 | size(T) 5 | size(H) 6 | end; 7 | 8 | N = length(T); 9 | numT = 0; 10 | numH = 0; 11 | numI = 0; 12 | for n=1:N, 13 | Tn = (T(n+1:end))==T(n); 14 | Hn = (H(n+1:end))==H(n); 15 | numT = numT + sum(Tn); 16 | numH = numH + sum(Hn); 17 | numI = numI + sum(Tn .* Hn); 18 | end; 19 | p = 1; 20 | r = 1; 21 | f = 1; 22 | if numH > 0, 23 | p = numI / numH; 24 | end; 25 | if numT > 0, 26 | r = numI / numT; 27 | end; 28 | if (p+r) == 0, 29 | f = 0; 30 | else 31 | f = 2 * p * r / (p + r); 32 | end; 33 | -------------------------------------------------------------------------------- /measure/compute_nmi.m: -------------------------------------------------------------------------------- 1 | function [nmi clust_ent] = compute_nmi (T, H) 2 | 3 | N = length(T); 4 | classes = unique(T); 5 | clusters = unique(H); 6 | num_class = length(classes); 7 | num_clust = length(clusters); 8 | 9 | %%compute number of points in each class 10 | for j=1:num_class 11 | index_class = (T(:)==classes(j)); 12 | D(j) = sum(index_class); 13 | end 14 | 15 | %%mutual information 16 | mi = 0; 17 | A = zeros(num_clust, num_class); 18 | avgent = 0; 19 | for i=1:num_clust 20 | %number of points in cluster 'i' 21 | index_clust = (H(:)==clusters(i)); 22 | B(i) = sum(index_clust); 23 | for j=1:num_class 24 | index_class = (T(:)==classes(j)); 25 | %%compute number of points in class 'j' that end up in cluster 'i' 26 | A(i,j) = sum(index_class.*index_clust); 27 | if (A(i,j) ~= 0) 28 | miarr(i,j) = A(i,j)/N * log2 (N*A(i,j)/(B(i)*D(j))); 29 | %%average entropy calculation 30 | avgent = avgent - (B(i)/N) * (A(i,j)/B(i)) * log2 (A(i,j)/B(i)); 31 | else 32 | miarr(i,j) = 0; 33 | end 34 | mi = mi + miarr(i,j); 35 | 36 | 37 | 38 | end 39 | end 40 | 41 | %%class entropy 42 | class_ent = 0; 43 | for i=1:num_class 44 | class_ent = class_ent + D(i)/N * log2(N/D(i)); 45 | end 46 | 47 | %%clustering entropy 48 | clust_ent = 0; 49 | for i=1:num_clust 50 | clust_ent = clust_ent + B(i)/N * log2(N/B(i)); 51 | end 52 | 53 | %%normalized mutual information 54 | nmi = 2*mi / (clust_ent + class_ent); -------------------------------------------------------------------------------- /measure/myNMIACCwithmean.m: -------------------------------------------------------------------------------- 1 | function [resmax]= myNMIACCwithmean(U,Y,numclass) 2 | 3 | stream = RandStream.getGlobalStream; 4 | reset(stream); 5 | U_normalized = U ./ repmat(sqrt(sum(U.^2, 2)), 1,size(U,2)); 6 | maxIter = 50; 7 | 8 | for iter = 1:maxIter 9 | indx = litekmeans(U_normalized,numclass,'MaxIter',100, 'Replicates',1); 10 | % indx = kmeans(U_normalized,numclass,'MaxIter',100, 'Replicates',1); 11 | indx = indx(:); 12 | result(iter,:) = Clustering8Measure(Y,indx); % result = [ACC nmi Purity Fscore Precision Recall AR Entropy]; 13 | end 14 | resmax = max(result,[],1); -------------------------------------------------------------------------------- /run.m: -------------------------------------------------------------------------------- 1 | clear; 2 | clc; 3 | 4 | addpath(genpath('./')); 5 | 6 | resultdir1 = 'Results/'; 7 | if (~exist('Results', 'file')) 8 | mkdir('Results'); 9 | addpath(genpath('Results/')); 10 | end 11 | 12 | resultdir2 = 'aResults/'; 13 | if (~exist('aResults', 'file')) 14 | mkdir('aResults'); 15 | addpath(genpath('aResults/')); 16 | end 17 | 18 | datadir='.\datasets\'; 19 | 20 | dataname={'MSRCV1_3v'}; 21 | 22 | numdata = length(dataname); % number of the test datasets 23 | numname = {'_Per0.1', '_Per0.2', '_Per0.3', '_Per0.4','_Per0.5', '_Per0.6', '_Per0.7', '_Per0.8', '_Per0.9'}; 24 | 25 | for idata =1:1:1 26 | ResBest = zeros(9,8); 27 | ResStd = zeros(9,8); 28 | for dataIndex = 1:1:9 29 | datafile = [datadir, cell2mat(dataname(idata)), cell2mat(numname(dataIndex)), '.mat']; 30 | load(datafile); 31 | %data preparation... 32 | gt = truelabel{1}; 33 | numview = length(data); 34 | cls_num = length(unique(gt)); 35 | k= cls_num; 36 | tic; 37 | [X1, ind] = findindex(data, index); 38 | time1 = toc; 39 | maxAcc = 0; 40 | TempLambda1 = [0.001 1 10]; 41 | TempLambda2 = [0.001 1 10]; 42 | ACC = zeros(length(TempLambda1),length(TempLambda2)); 43 | NMI = zeros(length(TempLambda1),length(TempLambda2)); 44 | Purity = zeros(length(TempLambda1),length(TempLambda2)); 45 | idx = 1; 46 | for LambdaIndex1 = 1 : length(TempLambda1) 47 | lambda1 = TempLambda1(LambdaIndex1); 48 | for LambdaIndex2 = 1 : length(TempLambda2) 49 | lambda2 = TempLambda2(LambdaIndex2); 50 | 51 | disp([char(dataname(idata)), char(numname(dataIndex)), '-l1=', num2str(lambda1), '-l2=', num2str(lambda2)]); 52 | tic; 53 | ini = 2; %Initialze G: 1:K-means 2:PCA 54 | [S,G,iter,obj] = SCSL(X1,gt,lambda1,lambda2,ind,index,ini); 55 | F = SpectralClustering((S+S')/2, cls_num); 56 | time2 = toc; 57 | stream = RandStream.getGlobalStream; 58 | reset(stream); 59 | MAXiter = 1000; % Maximum number of iterations for KMeans 60 | REPlic = 20; % Number of replications for KMeans 61 | tic; 62 | for rep = 1 : 20 63 | pY = kmeans(F, cls_num, 'maxiter', MAXiter, 'replicates', REPlic, 'emptyaction', 'singleton'); 64 | res(rep, : ) = Clustering8Measure(gt, pY); 65 | end 66 | time3 = toc; 67 | runtime(idx) = time1 + time2 + time3/20; 68 | disp(['runtime:', num2str(runtime(idx))]) 69 | idx = idx + 1; 70 | tempResBest(dataIndex, : ) = mean(res); 71 | tempResStd(dataIndex, : ) = std(res); 72 | ACC(LambdaIndex1,LambdaIndex2) = tempResBest(dataIndex, 1); 73 | NMI(LambdaIndex1,LambdaIndex2) = tempResBest(dataIndex, 2); 74 | Purity(LambdaIndex1,LambdaIndex2) = tempResBest(dataIndex, 3); 75 | save([resultdir1, char(dataname(idata)), char(numname(dataIndex)), '-l1=', num2str(lambda1), '-l2=', num2str(lambda2), ... 76 | '-acc=', num2str(tempResBest(dataIndex,1)), '_result.mat'], 'tempResBest', 'tempResStd'); 77 | for tempIndex = 1 : 8 78 | if tempResBest(dataIndex, tempIndex) > ResBest(dataIndex, tempIndex) 79 | ResBest(dataIndex, tempIndex) = tempResBest(dataIndex, tempIndex); 80 | ResStd(dataIndex, tempIndex) = tempResStd(dataIndex, tempIndex); 81 | end 82 | end 83 | end 84 | end 85 | aRuntime = mean(runtime); 86 | PResBest = ResBest(dataIndex, :); 87 | PResStd = ResStd(dataIndex, :); 88 | save([resultdir2, char(dataname(idata)), char(numname(dataIndex)), 'ACC_', num2str(max(ACC(:))), '_result.mat'], 'ACC', 'NMI', 'Purity', 'aRuntime', ... 89 | 'PResBest', 'PResStd'); 90 | end 91 | save([resultdir2, char(dataname(idata)), '_result.mat'], 'ResBest', 'ResStd'); 92 | end 93 | --------------------------------------------------------------------------------