用MATLAB做聚类分析时非常有用的自定义距离函数标准化函数
聚类分析中,经常遇到观测值缺失的情况.
例如统计历史降水资料时,某个月的资料缺失了,这时用MATLAB做聚类分析时,
就需要自定义距离函数,处理nan的问题.
下面是相关的MATLAB函数,里面有例子,可自行修改:
function [ nandistance ] = nandistfun( X,Y,varargin)
% A distance function for pdist,ignoring NaNs
% [ nandistance ] = nandistfun( X,Y,varargin)
% arguments :
% X: 1-by-n vector
% Y:m-by-n vector
% nandistance::m-by-1, whose kth element is the distance between X and Y(k,:).
%
% methods = {'euclidean'; 'seuclidean'; 'cityblock'; 'chebychev'; ...
% 'mahalanobis'; 'minkowski'; 'cosine'; 'correlation'; ...
% 'spearman'; 'hamming'; 'jaccard'};
%
% Example:
% >> X =[9, nan, 2, 4, 7; 8, 2, 9, nan, 5; 2, 5, 8, nan, 6];
% >> D = pdist(X,@nandistfun)
% >> D= pdist(X,@(a,b)nandistfun(a,b,'seu'))
%
% See also PDIST, SQUAREFORM, LINKAGE, SILHOUETTE, PDIST2.
%
%Author:Wu Xuping Date:2013-09-21 Version:1.0.0
[xrow,xcolumn]=size(X);
[yrow,ycolumn]=size(Y);
%可变参数的个数
nVarargs = length(varargin);
%初始化距离
nandistance=zeros(yrow,1);
if (xrow==1 && xcolumn==ycolumn)
for m=1:yrow
x1=X;%必须是行向量,不能是空向量
y1=Y(m,:);%必须是行向量,不能是空向量
b=( ~isnan(x1)) & (~isnan(y1)); %提取(x1,y1)中都不是nan的索引
A=[];
A(1,:)=x1(b);%必须是行向量,不能是空向量
A(2,:)=y1(b);%必须是行向量,不能是空向量
%计算距离
if (nVarargs>0)
nandistance(m,1) = pdist(A,varargin{:});
else
nandistance(m,1) = pdist(A); %默认'euc'
end
end
end
end
上面这个函数,包括了常用的各种距离函数.
看完了这个函数的实现方式,我想大家也可以自定义其它类型的距离函数了.
通常做聚类分析时先将数据标准化,matlab提供了zscore函数,不过不支持nans,
这时可以试试下面的函数:
function [ z ] = nanzscore( x )
%[ z ] = nanzscore( x ),ignoring NaNs
% 类似于标准化函数[ z ] = zscore( x ),忽略NaNs
% Author:wuxuping,Date:2013-09-21
nm=nanmean(x);
ns=nanstd(x);
[xrow,xcolumn]=size(x);
if ((xrow>1 )&&(xcolumn >1))
%如果是多行多列的矩阵
z=zeros(size(x));
for m=1:xrow
for n=1:xcolumn
z(m,n) = (x(m,n)- nm(n))./ns(n);
end
end
else
%如果是单行或单列的向量
if (xrow==1)
for m=1:numel(x)
z(m) = (x(m)- nm)./ns;%行向量
end
else
for m=1:numel(x)
z(m,1) = (x(m)- nm)./ns;%列向量
end
end
end
上面的标准化函数用起来和zscore是一样的,只是忽略所有的NaNs.
下面是一般的聚类分析过程:
x=dlmread(filename);
x=nanzscore( x );
D = pdist(x,@nandistfun);
%Y = squareform(D,'tomatrix')
Z=linkage(D,'average');
[H,T] =dendrogram(Z,'colorthreshold','default');
set(H,'LineWidth',2);
find(T==5)
聚类图如下: