diff scripts/statistics/base/ranks.m @ 4885:28ab079d8f0e

[project @ 2004-04-30 04:21:33 by jwe]
author jwe
date Fri, 30 Apr 2004 04:21:33 +0000
parents 38c61cbf086c
children 54b076a24718
line wrap: on
line diff
--- a/scripts/statistics/base/ranks.m	Fri Apr 30 04:12:37 2004 +0000
+++ b/scripts/statistics/base/ranks.m	Fri Apr 30 04:21:33 2004 +0000
@@ -18,37 +18,78 @@
 ## 02111-1307, USA.
 
 ## -*- texinfo -*-
-## @deftypefn {Function File} {} ranks (@var{x})
+## @deftypefn {Function File} {} ranks (@var{x}, @var{dim})
 ## If @var{x} is a vector, return the (column) vector of ranks of
 ## @var{x} adjusted for ties.
 ##
-## If @var{x} is a matrix, do the above for each column of @var{x}.
+## If @var{x} is a matrix, do the above for along the first 
+## non-singleton dimension. If the optional argument @var{dim} is
+## given, operate along this dimension.
 ## @end deftypefn
 
 ## Author: KH <Kurt.Hornik@ci.tuwien.ac.at>
 ## Description: Compute ranks
 
-## This code is rather ugly, but is there an easy way to get the ranks
-## adjusted for ties from sort?
+## This code was rather ugly, since it didn't use sort due to the
+## fact of how to deal with ties. Now it does use sort and its
+## even uglier!!! At least it handles NDArrays..
+
+function y = ranks (x, dim)
+
+  if (nargin != 1 && nargin != 2)
+    usage ("ranks (x, dim)");
+  endif
 
-function y = ranks (x)
-
-  if (nargin != 1)
-    usage ("ranks (x)");
+  nd = ndims (x);
+  sz = size (x);
+  if (nargin != 2)
+    %% Find the first non-singleton dimension
+    dim  = 1;
+    while (dim < nd + 1 && sz (dim) == 1)
+      dim = dim + 1;
+    endwhile
+    if (dim > nd)
+      dim = 1;
+    endif
+  else
+    if (! (isscalar (dim) && dim == round (dim)) && dim > 0 && 
+	dim < (nd + 1))
+      error ("ranks: dim must be an integer and valid dimension");
+    endif
   endif
 
-  y = [];
-
-  [r, c] = size (x);
-  if ((r == 1) && (c > 0))
-    p = x' * ones (1, c);
-    y = sum (p < p') + (sum (p == p') + 1) / 2;
-  elseif (r > 1)
-    o = ones (1, r);
-    for i = 1 : c;
-      p = x (:, i) * o;
-      y = [y, (sum (p < p') + (sum (p == p') + 1) / 2)'];
-    endfor
+  if (sz (dim) == 1)
+    y = ones(sz);
+  else
+    ## The algorithm works only on dim=1, so permute if necesary
+    if (dim != 1)
+      perm = [1 : nd];
+      perm (1) = dim;
+      perm (dim) = 1;
+      x = permute (x, perm);
+    endif
+    sz  = size (x);
+    infvec = -Inf * ones ([1, sz(2 : end)]);
+    [xs, y] = sort (x);
+    eq_el = find (diff ([xs; infvec]) == 0);
+    if (isempty (eq_el))
+      [eq_el, y] = sort (y);  
+    else
+      runs = complement (eq_el+1, eq_el);
+      runs = reshape (y (runs), size (runs)) + 
+             floor (runs ./ sz (1)) * sz(1);
+      len = diff (find (diff ([Inf; eq_el; -Inf]) != 1)) + 1;
+      [eq_el, y] = sort (y);  
+      for i = 1 : length(runs)
+	p = y (runs (i)) + (len (i) - 1) / 2;
+	for j = 0 : len (i) - 1
+	  y (runs (i) + j) = p;
+	endfor
+      endfor
+    endif  
+    if (dim != 1)
+      y = permute (y, perm);
+    endif
   endif
 
 endfunction