⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gemanova.m

📁 进行方差分析的MATLAB源码
💻 M
📖 第 1 页 / 共 4 页
字号:
 
 
 
 
 
 
 function model = parafac(x,nocomp,scl,tol,x0,options,plots,constraints,weights);

%PARAFAC Parallel factor analysis for n-way arrays
%  PARAFAC will decompose an array of order n (where n >= 3)
%  into the summation over the outer product of n vectors.
%  Missing values must be NaN or Inf.
%  
%  INPUTS
%  x           : the multi-way array to be decomposed
%  nocomp      : the number of components to estimate, 
%
%  OPTIONAL INPUTS
%  scl         : optional inputs of a cell array of vectors for plotting
%                loads against (set scl=[] for none, if elements of scl are
%                empty or of incorrect length they are reset),
%  tol         : convergence tolerance (a 1 by 3 vector consisting of 
%                the relative change in fit, absolute change in fit 
%                and maximum iterations {default tol = [1e-6 1e-6 10000]}), 
%  x0          : initial estimate of the factors, default is none = [].
%                x0 is a cell array of the same form as the fitted loadings
%                output in model.loads. Thus, x0{i} holds the loading matrix
%                in the i'th mode.
%                   If x0 is correctly provided, it will be used for initializing
%                the algorithm. Note, that if constraints(i) is set to -1, then
%                the loadings of that mode will not be updated, hence the initial
%                stay fixed. This way, one may use the algorithm for fitting an 
%                existing model to new data, by inputting the old model (model.loads) 
%                and fixing all except the sample mode loadings.
%                   It is also possible to input a complete PARAFAC model (a 
%                structure). This is useful when a prior model also includes
%                offsets, so that these are also used as initial values.
%  options     : A vector defining algorithmic settings:
%                options(1) = a flag which turns off the line search options when 0
%                options(2) = turns off screen output when set to zero
%                Default, options = [] = [1 1];
%  plots       : a flag which turns off the plotting of the loads and 
%                residuals when set to zero. 
%  constraints : Vector defining constraints. constraints has length equal to the number
%                of modes (for a three-way array, constraints is a 3-vector). 
%                constraints(1) =  0 => First mode loadings unconstrained
%                constraints(1) =  1 => First mode loadings nonnegativity-constrained
%                constraints(1) =  2 => First mode loadings unimodality-unconstrained (and nonneg)
%                constraints(1) =  3 => First mode loadings orthogonality-unconstrained
%                constraints(1) = -1 => First mode loadings fixed (requires initial values given)
%                constraints(2) =  ...  Defines constraints on second mode loadings
%                Example.: constraints = [0 1 2] means A unconstrained, B nonneg, & C unimodal
%  weights     : Enables weighted least squares fitting. Type <parafac('weights')> to get help on 
%                this feature
%
%  The output is a structured array (model) containing the 
%  PARAFAC model elements:
%
%     xname: name of the original workspace input variable
%      name: type of model, always 'PARAFAC'
%      date: model creation date stamp
%      time: model creation time stamp
%      size: size of the original input array
%     ncomp: number of components estimated
%       tol: tolerance vector used during model creation
%     final: final tolerances at termination
%       ssq: total and residual sum of squares
%     loads: 1 by order cell array of the loadings in each dimension
%       res: 1 by order cell array squared residuals summed over each dimension
%       scl: 1 by order cell array with scales for plotting loads 
%
%  This routine uses alternating least squares (ALS) in combination with
%  a line search every fifth iteration. For 3-way data, the intial estimate
%  of the loadings is obtained from the tri-linear decomposition (TLD).
%
%I/O: model = parafac(x,nocomp,scl,tol,x0,options,plots,constraints,weights,iteroff);
%
%See also:  GRAM, MPCA, MWFIT, OUTER, OUTERM, TLD, UNFOLDM, XPLDST

%Copyright Eigenvector Research, Inc. 1998-2000
%bmw March 4, 1998
%rb September, 1999 (added nnls, ulsr, fixed modes, orthogonality, weights, missing data, screendumps, moving the mode holding the scale in case the last mode is fixed)
%nbg 3/1/00 (check scl so routine doesn't bomb when not correct)
%rb March , 2000 (handle empty input for weights and constraints, do iteratively computed offsets)
%Ditto (included gui for help on iterative inputs)
%Ditto (corrected error so that old loading-values are accepted as cell arrays)
%rb April, 2000, corrects so that offsets can be included in old-values input, x0, by allowing a model struct to be input
%rb April, 2000, Fixed updating of unfolded X in linesearch when missing
%rb August, 2000, Added ATLD for initialization
%rb December, 2000, Fixed error in fixed mode loadings estimation
%rb February, 2001, removed iteroff (iterative offsets)


if nargin == 0
	disp(' ')
	disp(' PARAFAC Parallel factor analysis for n-way arrays - short help')
	disp(' ')
	disp(' I/O: model = parafac(x,nocomp,scl,tol,x0,options,plots,constraints,weights,iteroff);')
	disp(' ')
	disp(' Type <<help parafac>> for extended help')
	disp(' ')
	break
end

if nargin ==1
	if strcmp(lower(x),'weights')
		disp(' USING A WEIGHTED LOSS FUNCTION')
		disp(' ')
		disp(' Through the use of the input ''weights'' it is possible to fit a PARAFAC')
		disp(' model in a weighted least squares sense')
		disp(' ')
		disp(' The input is an array of the same size as the input data holding individual')
		disp(' weights for changing the loss function from a least squares to weighted least')
		disp(' squares one. Instead of minimizing the frobenius norm ||x-M|| where M is the PARAFAC')
		disp(' model, the norm ||(x-M).*weights|| is minimized. The algorithm used for')
		disp(' weighted regression is a majorization step according to Kiers, Psychometrika,')
		disp(' 1997, 62, 251-266, which has the advantage of being computationally cheap and ')
		disp(' also handles situations where ordinary weighted least squares regression does')
		disp(' not work.')
	end
	return
end



% INITIALIZATION OF ALGORITHM
Show = 100; % How often are fit values shown
xsize = size(x);
order = ndims(x);
if (nargin < 3 | ~strcmp(class(scl),'cell'))
	scl = cell(1,order);
end
for ii=1:order   %added 3/1/00 nbg
	if isempty(scl{ii})|(length(scl{ii})~=xsize(ii))
		scl{ii} = 1:xsize(ii);
	end
end
standardtol = [1e-6 1e-6 10000];
if (nargin < 4 | length(tol)==0)
	tol = standardtol;
else % Changed error rb 11/03/00
	tol(find(tol==0)) = standardtol(find(tol==0));
end
if nargin < 6
	options = [1 1];
end
if length(options)<2
	options = [options ones(1,2-length(options))];
end
ls = options(1); %For line-searh
DumpToScreen = options(2);
if nargin < 7|length(plots)==0
	plots = 1;
end
if nargin < 8
	constraints = zeros(1,order);
end
if length(constraints)~=order
	constraints = zeros(1,order);
end

if nargin < 9 
	DoWeight = 0;
else
	if length(size(weights))~=order 
		DoWeight = 0;
	elseif all(size(weights)==xsize)
		DoWeight = 1;
		WMax     = max(abs(weights(:)));
		W2       = weights.*weights;
	else
		DoWeight = 0;
	end
end

%Iterative preproc
iteroffsets = 0;
if exist('iteroff')==1
	if iscell(iteroff)
		iteroffsets = 1;
	elseif isnumeric(iteroff) % Then convert to cell
		hh = iteroff;
		clear iteroff
		iteroff{1} = hh;
		iteroffsets = 1;
	elseif ischar(iteroff)
		if strcmp(lower(iteroff(1:2)),'he')
			clear iteroff
			button = questdlg('Do you want help to incorporate offsets?','Offsets','Yes','No','Cancel','Yes');
			if strcmp(button,'Cancel')
				break
			elseif strcmp(button,'No')
				iteroffsets = 0;
			else
				Continue = 1;
				while Continue
					if Continue==1
						questdlg('For each type of offset, you input the number of the modes across which the offsets are constant. E.g. for a three-way array where you want ordinary offsets that are constant across the first mode (~average of each column); then you input the offset as [1], meaning the the offset is constant across the first mode. In this case the offsets will therefore be a matrix of dimension J x K (J second mode dimension, K third mode dimension). If you want an offset that is constant across all three modes, you input [1 2 3], implying that one offset is estimated','Offsets - how to do it','OK','OK');
					end
					prompt={['Enter the definition of offset # ',num2str(Continue)]};
					def={'[1]'};
					dlgTitle='Offset definition';
					lineNo=1;
					% Ask for offset
					Def=inputdlg(prompt,dlgTitle,lineNo,def);
					% If cancel is hit instead of OK
					if isempty(Def)
						hh=questdlg('Offsets across the first mode will be assumed','Drop offsets?','OK','Stop PARAFAC','OK');
						if strcmp(hh,'Stop PARAFAC')
							error(' PARAFAC stopped')
						else
							Def{1} = '[1]';
						end
					end
					% Verify the offset and show how it's implemented
					hh = eval(Def{1});
					txt = ['[',num2str(hh(1))];
					for i = 2:length(hh);
						txt = [txt,' ',num2str(hh(i))];
					end
					txt = [txt,']'];
					prompt={['Offset # ',num2str(Continue),' is defined as: iteroff{',num2str(Continue),'} = ',txt,';']};
					dlgTitle='Learn how to use the offset input <iteroff>';
					% Ask for offset
					questdlg(prompt,dlgTitle,'OK','Cancel','OK');
					iteroff{Continue} = eval(Def{1});
					Continue = Continue + 1;
					answer=questdlg('Do you want to incorporate other offsets?','More?','Yes','No','Yes');
					if strcmp(answer,'No')
						Continue = 0;
					end
				end
				iteroffsets = 1;
			end
		end
	end
end
if iteroffsets
	XTrilin = zeros(size(x));
	%   options(1) = 0; % No line-search can be performed as iterative offsets are not currently supported in the line-search
end

FeasibilityProblems = 0; % for indicating if the algorithm hasn't yet reached a feasible solution due some constraints
%Define in which mode the scale should go - default is last unless it's fixed')
if all(constraints==-1)
	error(' All modes are fixed, hence no fitting problem')
else
	if constraints(order)==-1 % Since last mode is fixed, scale of the components cannot go there. Instead use the first non-fixed mode
		ScaleMode = min(find(constraints~=-1));
	else
		ScaleMode = order;
	end
end

% CHECK FOR MISSING
if any(isinf(x(:)))|any(isnan(x(:)))
	MissId    = sparse(find(isinf(x)|isnan(x)));
	Missing   = 1;
else
	Missing = 0;
end


% INITIALIZE LOADINGS (if not already given)
if (nargin < 5 | ~(strcmp(class(x0),'cell') | strcmp(class(x0),'struct')))  % Old loadings not given
	x0 = cell(1,order);
	if all(xsize>nocomp) & ~Missing% Use atld
		x0=atld(x,nocomp,0);
		InitString = ' Using fast approximation for initialization';
	elseif order == 3&~Missing&~all(xsize<nocomp)
		% Initialize with TLD estimates
		m = tld(x,nocomp,0,0);
		x0 = m.loads;
		InitString = ' Using direct trilinear decomposition for initialization';
	else
		for j = 1:order
			x0{1,j} = rand(xsize(j),nocomp);
		end
		InitString = ' Using random values for initialization';
	end
else % Old loadings given
	if strcmp(class(x0),'cell')
		x0 = x0;
		InitString = ' Using old values for initialization';
	elseif strcmp(class(x0),'struct')
		if ~strcmp(x0.name,'PARAFAC')
			error(' Input x0 is model that is not a PARAFAC model (name in structure should be PARAFAC)')
		else
			% Use prior model given in x0 to extract loadings and possibly offsets
			if isfield(x0,'Offsets')  % If offsets are given in prior model, then include these
				iteroffsets = 1;
				iteroff = x0.Offsets.Def;
				for i=1:length(iteroff);
					Offset{i}.OffsetsReduced = x0.Offsets.Parameters{1};
					Offset{i}.Offsets = x0.Offsets.Model{1};
				end
				x0 = x0.loads;
				XTrilin = outerm(x0);%zeros(size(x));
				InitString = ' Using old values for initialization (including offsets)';
			else
				x0 = x0.loads;
				InitString = ' Using old values for initialization';
			end
		end
	elseif ~strcmp(class(x0),'cell')
		error('Initial estimate x0 not a cell array')
	end
end


% CHECK FOR INFEASIBLE INITIAL SOLUTIONS
if any(constraints)==1|any(constraints==2) % Nonnegativity required => make sure initial values are positive
	for j=1:order
		if constraints(j)==1|constraints(j)==2
			if any(x0{j}(:)<0) % Negative values occur
				x0{j} = sign(sum(sum(x0{j})))*x0{j}; %'Turn' it around so mainly positive
				i=find(x0{j}<0);
				x0{j}(i)=-x0{j}(i);
			end
		end
	end
end
if any(constraints==3) % Orth required
	for j=1:order
		if constraints(j)==3
			if size(x,j)<nocomp
				error([' Orthogonality cannot be applied in a mode (mode ',num2str(j),') where the dimension is less than the number of factors'])
			else
				x0{j} = orth(x0{j});
			end
		end
	end
end

if Missing % exchange missing elements with model estimates
	xest = outerm(x0);   % Old version;xest = zeros(prod(xsize),nocomp);   for j = 1:nocomp      xvect = x0{1}(:,j);      for ii = 2:order         xvect = xvect*x0{ii}(:,j)';         xvect = xvect(:);      end      xest(:,j) = xvect;   end,   xest = sum(xest,2);   xest = reshape(xest,xsize);
	XTrilin = xest; % Multilinear part to subtract from data before calculating offsets
	if iteroffsets & exist('Offset') % it doesn't exist unless prior model is input
		for i=1:length(iteroff) % estimate each set of offsets one at a time
			xest = xest + Offset{i}.Offsets;
		end
	end
	x(MissId)=xest(MissId);
end
% Calculate total sum of squares in data
if DoWeight
	xsq = (x.*weights).^2;
else
	xsq = x.^2;
end
if Missing
	xsq(MissId)=0;  
end
tssq = sum(xsq(:));

% Initialize the unfolded matrices
xuf = cell(1,order);
xuflo = cell(1,order);
xufsize = zeros(1,order);
for i = 1:order
	xuf{i} = unfoldmw(x,i)';
	xufsize(i) = prod(xsize)/xsize(i);
	% Old init of loads;xuflo{i} = zeros(prod(xsize)/xsize(i),nocomp);
	for j = 1:nocomp
		% Old version if i == 1,         mwvect = x0{2}(:,j);,         for k = 3:order              mwvect = mwvect*x0{k}(:,j)';            mwvect = mwvect(:);         end      else         mwvect = x0{1}(:,j);         for k = 2:order            if k ~= i               mwvect = mwvect*x0{k}(:,j)';               mwvect = mwvect(:);            end         end      end      xuflo{i}(:,j) = mwvect;   end
		xuflo{j}=outerm(x0,j,1);
	end
end

% Initialize other variables needed in the ALS
oldx0 = x0;
searchdir = x0;
iter = 0;
flag = 0;
oldests = zeros(prod(xsize)*nocomp,1);
abschange = 0;
relchange = 0;


% Show algorithmic settings etc.
if DumpToScreen
	disp(' ')
	disp(' Fitting PARAFAC ...') 
	txt=[];
	for i=1:order-1
		txt=[txt num2str(xsize(i)) ' x '];
	end
	txt=[txt num2str(xsize(order))];
	disp([' Input: ',num2str(order),'-way ',txt, ' array'])
	
	disp([' A ',num2str(nocomp),'-component model will be fitted'])
	for i=1:order
		if constraints(i)==0
			disp([' No constraints on mode ',num2str(i)])
		elseif constraints(i)==1
			disp([' Nonnegativity on mode ',num2str(i)])
		elseif constraints(i)==2
			disp([' Unimodality on mode ',num2str(i)])
		elseif constraints(i)==3
			disp([' Orthogonality on mode ',num2str(i)])
		elseif constraints(i)==-1
			disp([' Fixed loadings in mode ',num2str(i)])
		end
	end
	
	disp([' Convergence criteria:']) 
	disp([' Relative change in fit : ',num2str(tol(1))]) 
	disp([' Absolute change in fit : ',num2str(tol(2))]) 
	disp([' Maximum iterations     : ',num2str(tol(3))]) 
	
	if Missing
		disp([' ', num2str(100*(length(MissId)/prod(xsize))),'% missing values']);
	else
		disp(' No missing values')
	end
	
	if DoWeight
		disp(' Weighted optimization will be performed using input weights')
	end
	
	%Iterative preproc
	if iteroffsets
		disp(' Iteratively calculated offsets will be used')
		disp(' Line-search has been turned off')
	else
		%disp(' No iterative offsets')
	end
	
	disp(InitString)
end

% Start the ALS
while flag == 0;
	iter = iter+1;
	% Loop over each of the order to estimate
	
	if DoWeight & iter > 1% If Weighted regression is to be used, do majorization to make a transformed data array to be fitted in a least squares sense
		out = reshape(xest,xsize) + (WMax^(-2)*W2).*(x - reshape(xest,xsize));
		for i = 1:order
			xuf{i} = unfoldmw(out,i)';
		end
		clear out
	end
	
	%Iterative preproc
	if iteroffsets
		if iter>1
			OldOffset = Offset;
		end
		if DoWeight & Iter > 1 % Then the data to fit is not the raw data in x but the modified data according to above in xuf
			xprep = reshape(xuf{1}',xsize) - Xtrilin;
		else
			xprep = x - XTrilin;
		end

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -