Mercurial > forge
changeset 12322:312fb4e2ef6d octave-forge
new cmdscale
author | nir-krakauer |
---|---|
date | Mon, 20 Jan 2014 22:01:42 +0000 |
parents | 46513ae1cc51 |
children | e776ad2d130c |
files | main/statistics/INDEX main/statistics/NEWS main/statistics/inst/cmdscale.m |
diffstat | 3 files changed, 62 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/main/statistics/INDEX Fri Jan 17 15:28:18 2014 +0000 +++ b/main/statistics/INDEX Mon Jan 20 22:01:42 2014 +0000 @@ -74,6 +74,7 @@ Fitting gamfit Clustering + cmdscale kmeans linkage pdist
--- a/main/statistics/NEWS Fri Jan 17 15:28:18 2014 +0000 +++ b/main/statistics/NEWS Mon Jan 20 22:01:42 2014 +0000 @@ -1,3 +1,10 @@ +Summary of important user-visible changes for statistics 1.2.4: +------------------------------------------------------------------- + + ** The following functions are new: + + cmdscale + Summary of important user-visible changes for statistics 1.2.3: -------------------------------------------------------------------
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main/statistics/inst/cmdscale.m Mon Jan 20 22:01:42 2014 +0000 @@ -0,0 +1,54 @@ +## Copyright (C) 2014 Nir Krakauer +## +## This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. +## +## This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>. + +## -*- texinfo -*- +## @deftypefn {Function File} @var{Y} = cmdscale (@var{D}) +## @deftypefnx{Function File} [@var{Y}, @var{e}] = cmdscale (@var{D}) +## Classical multidimensional scaling of a matrix. Also known as principal coordinates analysis. +## +## Given an @var{n} by @var{n} Euclidean distance matrix @var{D}, find @var{n} points in @var{p} dimensional space which have this distance matrix. The coordinates of the points @var{Y} are returned. +## +## @var{D} should be a full distance matrix (hollow, symmetric, entries obeying the triangle inequality), or can be a vector of length @code{n(n-1)/2} containing the upper triangular elements of the distance matrix (such as that returned by the pdist function). If @var{D} is not a valid distance matrix, points @var{Y} will be returned whose distance matrix approximates @var{D}. +## +## The returned @var{Y} is an @var{n} by @var{p} matrix showing possible coordinates of the points in @var{p} dimensional space (@code{p < n}). Of course, any translation, rotation, or reflection of these would also have the same distance matrix. +## +## Can also return the eigenvalues @var{e} of @code{(D(1, :) .^ 2 + D(:, 1) .^ 2 - D .^ 2) / 2}, where the number of positive eigenvalues determines @var{p}. +## +## Reference: Rudolf Mathar (1985), The best Euclidian fit to a given distance matrix in prescribed dimensions, Linear Algebra and its Applications, 67: 1-6, doi: 10.1016/0024-3795(85)90181-8 +## +## @seealso{pdist, squareform} +## @end deftypefn + +## Author: Nir Krakauer <nkrakauer@ccny.cuny.edu> +## Description: Classical multidimensional scaling + +function [Y, e] = cmdscale (D) + + if isvector (D) + D = squareform (D); + endif + + warning ("off", "Octave:broadcast","local"); + M = (D(1, :) .^ 2 + D(:, 1) .^ 2 - D .^ 2) / 2; + + [v e] = eig(M); + + e = diag(e); + pe = (e > 0); #positive eigenvalues + + Y = v(:, pe) * diag(sqrt(e(pe))); + + +endfunction + + +%!shared m, n, X, D +%! m = 4; n = 3; X = rand(m, n); D = pdist(X); +%!assert(pdist(cmdscale(D)), D, m*n*eps) +%!assert(pdist(cmdscale(squareform(D))), D, m*n*eps) +