[Numpy-svn] r4888 - in trunk/numpy/lib: . tests

numpy-svn at scipy.org numpy-svn at scipy.org
Tue Mar 18 21:33:15 EDT 2008


Author: dhuard
Date: 2008-03-18 20:33:11 -0500 (Tue, 18 Mar 2008)
New Revision: 4888

Modified:
   trunk/numpy/lib/function_base.py
   trunk/numpy/lib/tests/test_function_base.py
Log:
Clean up of average function. weights now should have the same shape as a, or be 1D with length equal to the shape of a along axis. A number of tests are added.

Modified: trunk/numpy/lib/function_base.py
===================================================================
--- trunk/numpy/lib/function_base.py	2008-03-18 23:17:50 UTC (rev 4887)
+++ trunk/numpy/lib/function_base.py	2008-03-19 01:33:11 UTC (rev 4888)
@@ -327,66 +327,50 @@
 
 
 def average(a, axis=None, weights=None, returned=False):
-    """Average the array over the given axis.
+    """Return the weighted average of array a over the given axis.
+       
     
-    Average over the specified axis using the given weights. The average is
-    taken over all array elements by default. The default values of the
-    weights is one. When the weights are given, then they must be
-    broadcastable to the shape of a when the average is taken over all
-    elements, otherwise they must fill a 1D array of the same length as the
-    axis.
-
     Parameters
     ----------
     a : array_like
-        Array containing data to be averaged.
+        Data to be averaged.
     axis : {None, integer}, optional
-        Axis to be averaged over. If axis is None, the the average is taken
-        over all elements in the array.
+        Axis along which to average a. If None, averaging is done over the 
+        entire array irrespective of its shape. 
     weights : {None, array_like}, optional
-        A weighted average is formed using the given weights. If weights=None
-        then all weights are taken to be one. If axis=None, the the shape of
-        the weights must be broadcastable to the shape of a, other wise
-        weights must be 1D and of the same length as the specified axis.
+        The importance each datum has in the computation of the 
+        average. The weights array can either be 1D, in which case  its length 
+        must be the size of a along the given axis, or of the same shape as a. 
+        If weights=None, all data are assumed to have weight equal to one. 
     returned :{False, boolean}, optional
-        When true, then a tuple (average, sum_of_weights) is returned,
-        otherwise just the average. If the weights are all one the sum of the
-        weights will also be the number of elements averaged over.
+        If True, the tuple (average, sum_of_weights) is returned,
+        otherwise only the average is returmed. Note that if weights=None, then 
+        the sum of the weights is also the number of elements averaged over.
 
     Returns
     -------
     average, [sum_of_weights] : {array_type, double}
-        Returns the average along the specified axis by default. When returned
-        is True, the returns a tuple with the average as the first element and
-        the sum of the weights as the second element. The return type is
-        Float if a is of integer type, otherwise it is of the same type as a.
-        When returned, sum_of_weights is a scalar with the same type as the
-        average.
+        Return the average along the specified axis. When returned is True, 
+        return a tuple with the average as the first element and the sum 
+        of the weights as the second element. The return type is Float if a is 
+        of integer type, otherwise it is of the same type as a.
+        sum_of_weights is has the same type as the average.
 
+    
+    Example
+    -------
+      >>> average(range(1,11), weights=range(10,0,-1))
+      4.0
+    
     Exceptions
     ----------
     ZeroDivisionError
-        Results when all weights are zero.if appropriate. The version in MA
-        does not, it returns masked values.
+        Raised when all weights along axis are zero. See numpy.ma.average for a 
+        version robust to this type of error. 
     TypeError
-        Results when both an axis and weights are specified and the weights are
-        not an 1D array.
-
-    Notes
-    -----
-    The default behavior is equivalent to
-
-        a.mean(axis).
-
-    If weights are given, and axis=None, then the result is equivalent to
-
-        sum(a * weights) / (a.size/weights.size)*sum(weights)),
-
-    In the case when the axis is not the default, then the result is equivalent
-    to weights broadcast over the specified axis, then
-
-        sum(a * weights)/sum(weights)
-
+        Raised when the length of 1D weights is not the same as the shape of a 
+        along axis. 
+    
     """
     if not isinstance(a, np.matrix) :
         a = np.asarray(a)
@@ -397,19 +381,27 @@
     else :
         a = a + 0.0
         wgt = np.array(weights, dtype=a.dtype, copy=0)
-        scl = wgt.sum()
-        if axis is not None and wgt.ndim != 1 :
-            raise TypeError, 'Weights must be 1D when axis is specified'
-        if scl == 0.0:
-            raise ZeroDivisionError, "Weights sum to zero, can't be normalized"
 
-        if axis is None :
-            scl = scl*(a.size/wgt.size)
-        else:
+        # Sanity checks
+        if a.shape != wgt.shape :
+            if axis is None :
+                raise TypeError, "Axis must be specified when shapes of a and weights differ."
+            if wgt.ndim != 1 :
+                raise TypeError, "1D weights expected when shapes of a and weights differ."
+            if wgt.shape[0] != a.shape[axis] :
+                raise ValueError, "Length of weights not compatible with specified axis."
+    
+            # setup wgt to broadcast along axis
             wgt = np.array(wgt, copy=0, ndmin=a.ndim).swapaxes(-1,axis)
+
+        scl = wgt.sum(axis=axis)
+        if (scl == 0.0).any():
+            raise ZeroDivisionError, "Weights sum to zero, can't be normalized"
+
         avg = np.multiply(a,wgt).sum(axis)/scl
 
     if returned:
+        scl = np.multiply(avg,0) + scl
         return avg, scl
     else:
         return avg

Modified: trunk/numpy/lib/tests/test_function_base.py
===================================================================
--- trunk/numpy/lib/tests/test_function_base.py	2008-03-18 23:17:50 UTC (rev 4887)
+++ trunk/numpy/lib/tests/test_function_base.py	2008-03-19 01:33:11 UTC (rev 4888)
@@ -57,26 +57,64 @@
         assert_almost_equal(y5.mean(0), average(y5, 0))
         assert_almost_equal(y5.mean(1), average(y5, 1))
 
-    def check_weighted(self):
+        y6 = matrix(rand(5,5))
+        assert_array_equal(y6.mean(0), average(y6,0)) 
+               
+    def check_weights(self):
+        y = arange(10)
+        w = arange(10)
+        assert_almost_equal(average(y, weights=w), (arange(10)**2).sum()*1./arange(10).sum())
+    
         y1 = array([[1,2,3],[4,5,6]])
-        actual = average(y1,weights=[1,2],axis=0)
+        w0 = [1,2]
+        actual = average(y1,weights=w0,axis=0)
         desired = array([3.,4.,5.])
         assert_almost_equal(actual, desired)
         
-    def check_shape(self):
-        y = array([[1,2,3],[4,5,6]])
-
-        # this is not a valid test as documented in average. Should it be?
-        #w2 = [[0,0,1],[0,0,1]]
-        #desired = array([3., 6.])
-        #assert_array_equal(average(y, weights=w2, axis=1), desired)
         
         w1 = [0,0,1]
         desired = array([3., 6.])
-        assert_almost_equal(average(y, weights=w1, axis=1), desired)
+        assert_almost_equal(average(y1, weights=w1, axis=1), desired)
+
+        # This should raise an error. Can we test for that ?
+        # assert_equal(average(y1, weights=w1), 9./2.)
         
+    
+        # 2D Case
+        w2 = [[0,0,1],[0,0,2]]
+        desired = array([3., 6.])
+        assert_array_equal(average(y1, weights=w2, axis=1), desired)
+        
+        assert_equal(average(y1, weights=w2), 5.)
+        
+        
+    def check_returned(self):
+        y = array([[1,2,3],[4,5,6]])
 
+        # No weights
+        avg, scl = average(y, returned=True)
+        assert_equal(scl, 6.)
 
+        avg, scl = average(y, 0, returned=True)
+        assert_array_equal(scl, array([2.,2.,2.]))
+        
+        avg, scl = average(y, 1, returned=True)
+        assert_array_equal(scl, array([3.,3.]))
+        
+        # With weights
+        w0 = [1,2]
+        avg, scl = average(y, weights=w0, axis=0, returned=True)
+        assert_array_equal(scl, array([3., 3., 3.]))
+        
+        w1 = [1,2,3]
+        avg, scl = average(y, weights=w1, axis=1, returned=True)
+        assert_array_equal(scl, array([6., 6.]))
+        
+        w2 = [[0,0,1],[1,2,3]]
+        avg, scl = average(y, weights=w2, axis=1, returned=True)
+        assert_array_equal(scl, array([1.,6.]))
+    
+
 class TestSelect(NumpyTestCase):
     def _select(self,cond,values,default=0):
         output = []




More information about the Numpy-svn mailing list