function [pval table] = circ_wwtest(varargin) % [pval, table] = circ_wwtest(alpha, idx, [w]) % [pval, table] = circ_wwtest(alpha1, alpha2, [w1, w2]) % Parametric Watson-Williams multi-sample test for equal means. Can be % used as a one-way ANOVA test for circular data. % % H0: the s populations have equal means % HA: the s populations have unequal means % % Note: % Use with binned data is only advisable if binning is finer than 10 deg. % In this case, alpha is assumed to correspond % to bin centers. % % The Watson-Williams two-sample test assumes underlying von-Mises % distributrions. All groups are assumed to have a common concentration % parameter k. % % Input: % alpha angles in radians % idx indicates which population the respective angle in alpha % comes from, 1:s % [w number of incidences in case of binned angle data] % % Output: % pval p-value of the Watson-Williams multi-sample test. Discard H0 if % pval is small. % table cell array containg the ANOVA table % % PHB 3/19/2009 % % References: % Biostatistical Analysis, J. H. Zar % % Circular Statistics Toolbox for Matlab % By Philipp Berens, 2009 % berens@tuebingen.mpg.de - www.kyb.mpg.de/~berens/circStat.html [alpha, idx, w] = processInput(varargin{:}); % number of groups u = unique(idx); s = length(u); % number of samples n = sum(w); % compute relevant quantitites pn = zeros(s,1); pr = pn; for t=1:s pidx = idx == u(t); pn(t) = sum(pidx.*w); pr(t) = circ_r(alpha(pidx),w(pidx)); end r = circ_r(alpha,w); rw = sum(pn.*pr)/n; % make sure assumptions are satisfied checkAssumption(rw,mean(pn)) % test statistic kk = circ_kappa(rw); beta = 1+3/(8*kk); % correction factor A = sum(pr.*pn) - r*n; B = n - sum(pr.*pn); F = beta * (n-s) * A / (s-1) / B; pval = 1 - fcdf(F,s-1,n-s); na = nargout; if na < 2 printTable; end prepareOutput; function printTable fprintf('\nANALYSIS OF VARIANCE TABLE (WATSON-WILLIAMS TEST)\n\n'); fprintf('%s\t\t\t\t%s\t%s\t\t%s\t\t%s\t\t\t%s\n', ' ' ,'d.f.', 'SS', 'MS', 'F', 'P-Value'); fprintf('--------------------------------------------------------------------\n'); fprintf('%s\t\t\t%u\t\t%.2f\t%.2f\t%.2f\t\t%.4f\n', 'Columns', s-1 , A, A/(s-1), F, pval); fprintf('%s\t\t%u\t\t%.2f\t%.2f\n', 'Residual ', n-s, B, B/(n-s)); fprintf('--------------------------------------------------------------------\n'); fprintf('%s\t\t%u\t\t%.2f', 'Total ',n-1,A+B); fprintf('\n\n') end function prepareOutput if na > 1 table = {'Source','d.f.','SS','MS','F','P-Value'; ... 'Columns', s-1 , A, A/(s-1), F, pval; ... 'Residual ', n-s, B, B/(n-s), [], []; ... 'Total',n-1,A+B,[],[],[]}; end end end function checkAssumption(rw,n) if n > 10 && rw<.45 warning('Test not applicable. Average resultant vector length < 0.45.') %#ok elseif n > 6 && rw<.5 warning('Test not applicable. Average number of samples per population < 11 and average resultant vector length < 0.5.') %#ok elseif n >=5 && rw<.55 warning('Test not applicable. Average number of samples per population < 7 and average resultant vector length < 0.55.') %#ok elseif n < 5 warning('Test not applicable. Average number of samples per population < 5.') %#ok end end function [alpha, idx, w] = processInput(varargin) if nargin == 4 alpha1 = varargin{1}(:); alpha2 = varargin{2}(:); w1 = varargin{3}(:); w2 = varargin{4}(:); alpha = [alpha1; alpha2]; idx = [ones(size(alpha1)); ones(size(alpha2))]; w = [w1; w2]; elseif nargin==2 && sum(abs(round(varargin{2})-varargin{2}))>1e-5 alpha1 = varargin{1}(:); alpha2 = varargin{2}(:); alpha = [alpha1; alpha2]; idx = [ones(size(alpha1)); 2*ones(size(alpha2))]; w = ones(size(alpha)); elseif nargin==2 alpha = varargin{1}(:); idx = varargin{2}(:); if ~(size(idx,1)==size(alpha,1)) error('Input dimensions do not match.') end w = ones(size(alpha)); elseif nargin==3 alpha = varargin{1}(:); idx = varargin{2}(:); w = varargin{3}(:); if ~(size(idx,1)==size(alpha,1)) error('Input dimensions do not match.') end if ~(size(w,1)==size(alpha,1)) error('Input dimensions do not match.') end else error('Invalid use of circ_wwtest. Type help circ_wwtest.') end end