[Scipy-svn] r3346 - trunk/scipy/sandbox/timeseries

scipy-svn@scip... scipy-svn@scip...
Fri Sep 21 11:02:48 CDT 2007


Author: mattknox_ca
Date: 2007-09-21 11:01:23 -0500 (Fri, 21 Sep 2007)
New Revision: 3346

Modified:
   trunk/scipy/sandbox/timeseries/tseries.py
Log:
- fixed error with default value for func parameter in convert function
- updated some documentation

Modified: trunk/scipy/sandbox/timeseries/tseries.py
===================================================================
--- trunk/scipy/sandbox/timeseries/tseries.py	2007-09-21 15:33:16 UTC (rev 3345)
+++ trunk/scipy/sandbox/timeseries/tseries.py	2007-09-21 16:01:23 UTC (rev 3346)
@@ -54,19 +54,49 @@
 'first_unmasked_val', 'last_unmasked_val'
            ]
 
-def first_unmasked_val(a):
-    "Returns the first unmasked value in a 1d maskedarray."
-    (i,j) = MA.extras.flatnotmasked_edges(a)
-    return a[i]
+def _unmasked_val(marray, x):
+    "helper function for first_unmasked_val and last_unmasked_val"
+    try:
+        assert(marray.ndim == 1)
+    except AssertionError:
+        raise ValueError("array must have ndim == 1")
+    
+    idx = MA.extras.flatnotmasked_edges(marray)
+    if idx is None:
+        return MA.masked
+    return marray[idx[x]]
 
-def last_unmasked_val(a):
-    "Returns the last unmasked value in a 1d maskedarray."
-    (i,j) = MA.extras.flatnotmasked_edges(a)
-    return a[j]
+def first_unmasked_val(marray):
+    """Retrieve the first unmasked value in a 1d maskedarray.
 
-#### --------------------------------------------------------------------------
+*Parameters*:
+    marray : {MaskedArray}
+        marray must be 1 dimensional.
+
+*Returns*:
+    val : {marray.dtype}
+        first unmasked value in marray. If all values in marray are masked,
+        the function returns the maskedarray.masked constant
+"""
+    return _unmasked_val(marray, 0)
+
+def last_unmasked_val(marray):
+    """Retrieve the last unmasked value in a 1d maskedarray.
+
+*Parameters*:
+    marray : {MaskedArray}
+        marray must be 1 dimensional.
+
+*Returns*:
+    val : {marray.dtype}
+        last unmasked value in marray. If all values in marray are masked,
+        the function returns the maskedarray.masked constant
+"""
+    return _unmasked_val(marray, 1)
+
+#### -------------------------------------------------------------------------
 #--- ... TimeSeriesError class ...
-#### --------------------------------------------------------------------------
+#### -------------------------------------------------------------------------
 class TimeSeriesError(Exception):
     "Class for TS related errors."
     def __init__ (self, value=None):
@@ -109,16 +139,19 @@
             return False
     else:
         step_diff = a._dates.get_steps() != b._dates.get_steps()
-        if (step_diff is True) or (hasattr(step_diff, "any") and step_diff.any()):
+        if (step_diff is True) or \
+           (hasattr(step_diff, "any") and step_diff.any()):
             if raise_error:
                 raise TimeSeriesCompatibilityError('time_steps',
-                                                   a._dates.get_steps(), b._dates.get_steps())
+                                                   a._dates.get_steps(),
+                                                   b._dates.get_steps())
             else:
                 return False
         elif a.shape != b.shape:
             if raise_error:
-                raise TimeSeriesCompatibilityError('size', "1: %s" % str(a.shape),
-                                                       "2: %s" % str(b.shape))
+                raise TimeSeriesCompatibilityError(
+                        'size', "1: %s" % str(a.shape),
+                        "2: %s" % str(b.shape))
             else:
                 return False
     return True
@@ -156,7 +189,7 @@
     return True
 
 
-def _datadatescompat(data,dates):
+def _datadatescompat(data, dates):
     """Checks the compatibility of dates and data at the creation of a TimeSeries.
     Returns True if everything's fine, raises an exception otherwise."""
     # If there's only 1 element, the date is a Date object, which has no size...
@@ -166,7 +199,6 @@
     if dsize == tsize:
         return True
     elif data.ndim > 1:
-        #dsize = numeric.asarray(data.shape)[:-1].prod()
         dsize = data.shape[0]
         if dsize == tsize:
             return True
@@ -194,9 +226,9 @@
             "All series must have same frequency! (got %s instead)" % unique_freqs
     return common_freq
 
-##### --------------------------------------------------------------------------
+##### ------------------------------------------------------------------------
 ##--- ... Time Series ...
-##### --------------------------------------------------------------------------
+##### ------------------------------------------------------------------------
 class _tsmathmethod(object):
     """Defines a wrapper for arithmetic array methods (add, mul...).
 When called, returns a new TimeSeries object, with the new series the result of
@@ -205,12 +237,12 @@
     """
     def __init__ (self, methodname):
         self._name = methodname
-    #
+
     def __get__(self, obj, objtype=None):
         "Gets the calling object."
         self.obj = obj
         return self
-    #
+
     def __call__ (self, other, *args):
         "Execute the call behavior."
         instance = self.obj
@@ -229,22 +261,22 @@
 
 class _tsarraymethod(object):
     """Defines a wrapper for basic array methods.
-When called, returns a new TimeSeries object, with the new series the result of
-the method applied on the original series.
+When called, returns a new TimeSeries object, with the new series the result
+of the method applied on the original series.
 If `ondates` is True, the same operation is performed on the `_dates`.
 If `ondates` is False, the `_dates` part remains unchanged.
-    """
+"""
     def __init__ (self, methodname, ondates=False):
         """abfunc(fillx, filly) must be defined.
            abinop(x, filly) = x for all x to enable reduce.
         """
         self._name = methodname
         self._ondates = ondates
-    #
+
     def __get__(self, obj, objtype=None):
         self.obj = obj
         return self
-    #
+
     def __call__ (self, *args):
         "Execute the call behavior."
         _name = self._name
@@ -260,18 +292,19 @@
 
 class _tsaxismethod(object):
     """Defines a wrapper for array methods working on an axis (mean...).
-When called, returns a ndarray, as the result of the method applied on the series.
-    """
+When called, returns a ndarray, as the result of the method applied on the
+series.
+"""
     def __init__ (self, methodname):
         """abfunc(fillx, filly) must be defined.
            abinop(x, filly) = x for all x to enable reduce.
         """
         self._name = methodname
-    #
+
     def __get__(self, obj, objtype=None):
         self.obj = obj
         return self
-    #
+
     def __call__ (self, *args, **params):
         "Execute the call behavior."
         (_dates, _series) = (self.obj._dates, self.obj._series)
@@ -285,40 +318,51 @@
                 if axis in [-1, _series.ndim-1]:
                     result = result.view(type(self.obj))
                     result._dates = _dates
-#                    result = TimeSeries(result, dates=_dates)
             except IndexError:
                 pass
             return result
 
 class TimeSeries(MaskedArray, object):
     """Base class for the definition of time series.
-A time series is here defined as the combination of three arrays:
 
-    - `series` : *[ndarray]*
+A time series is here defined as the combination of two arrays:
+
+    series : {MaskedArray}
         Data part
-    - `mask` : *[ndarray]*
-        Mask part
-    - `dates` : *[DateArray]*
+    dates : {DateArray}
         Date part
 
-The combination of `series` and `dates` is the `data` part.
-    """
-    options = None
+*Construction*:
+    data : {array_like}
+        data portion of the array. Any data that is valid for constructing a
+        MaskedArray can be used here.
+    dates : {DateArray}
+
+*Other Parameters*:
+    all other parameters are the same as for MaskedArray. Please see the
+    documentation for the MaskedArray class in the maskedarray module
+    for details.
+
+*Notes*:
+    it is typically recommended to use the `time_series` function for
+    construction as it allows greater flexibility and convenience.
+"""
     _genattributes = ['fill_value']
-    def __new__(cls, data, dates, mask=nomask,
-                dtype=None, copy=False, fill_value=None, subok=True,
-                keep_mask=True, small_mask=True, hard_mask=False, **options):
-        maparms = dict(copy=copy, dtype=dtype, fill_value=fill_value,subok=subok,
+    def __new__(cls, data, dates, mask=nomask, dtype=None, copy=False,
+                fill_value=None, subok=True, keep_mask=True, small_mask=True,
+                hard_mask=False, **options):
+
+        maparms = dict(copy=copy, dtype=dtype, fill_value=fill_value, subok=subok,
                        keep_mask=keep_mask, small_mask=small_mask,
-                       hard_mask=hard_mask,)
+                       hard_mask=hard_mask)
         _data = MaskedArray(data, mask=mask, **maparms)
 
-        # Get the dates ..............................
+        # Get the dates ......................................................
         if not isinstance(dates, (Date, DateArray)):
-            raise TypeError("The input dates should be a valid Date or DateArray object! "\
-                            "(got %s instead)" % type(dates))
+            raise TypeError("The input dates should be a valid Date or " + \
+                            "DateArray object (got %s instead)" % type(dates))
 
-        # Get the data ...............................
+        # Get the data .......................................................
         if not subok or not isinstance(_data,TimeSeries):
             _data = _data.view(cls)
         if _data is masked:
@@ -338,24 +382,24 @@
             elif dates._unsorted is not None:
                 _data = _data[dates._unsorted]
         return _data
-    #............................................
+    #.........................................................................
     def __array_finalize__(self,obj):
         MaskedArray.__array_finalize__(self, obj)
         self._dates = getattr(obj, '_dates', DateArray([]))
         return
-    #..................................
+    #.........................................................................
     def __array_wrap__(self, obj, context=None):
         result = super(TimeSeries, self).__array_wrap__(obj, context)
         result._dates = self._dates
         return result
-    #............................................
+    #.........................................................................
     def _get_series(self):
         "Returns the series as a regular masked array."
         if self._mask.ndim == 0 and self._mask:
             return masked
         return self.view(MaskedArray)
     _series = property(fget=_get_series)
-    #............................................
+    #.........................................................................
     def __checkindex(self, indx):
         "Checks the validity of an index."
         if isinstance(indx, int):
@@ -385,9 +429,6 @@
             if self._dates.size == self.size:
                 return (indx, indx)
             return (indx,indx[0])
-#            elif len(indx)==2:
-#                return (indx,indx[0])
-#            return (indx,indx[:-1])
         elif isTimeSeries(indx):
             indx = indx._series
         if getmask(indx) is not nomask:
@@ -397,8 +438,8 @@
 
     def __getitem__(self, indx):
         """x.__getitem__(y) <==> x[y]
-Returns the item described by i. Not a copy as in previous versions.
-        """
+Returns the item described by i. Not a copy.
+"""
         (sindx, dindx) = self.__checkindex(indx)
         newdata = numeric.array(self._series[sindx], copy=False, subok=True)
         newdate = self._dates[dindx]
@@ -416,36 +457,11 @@
         newdata = newdata.view(type(self))
         newdata._dates = newdate
         return newdata
-# CHECK : The implementation below should work, but does not. Why ?
-#        newdata = numeric.array(self._data[sindx], copy=False)
-#        newdates = self._dates[dindx]
-#        if self._mask is not nomask:
-#            newmask = self._mask.copy()[sindx]
-#        else:
-#            newmask = nomask
-#        singlepoint = (len(numeric.shape(newdates))==0)
-#        if singlepoint:
-#            if newmask.ndim == 0 and newmask:
-#                output = tsmasked
-#                output._dates = newdates
-#                return output
-#            if self.ndim > 1:
-#                # CHECK: use reshape, or set shape ?
-#                newdata = newdata.reshape((list((1,)) + list(newdata.shape)))
-#                if newmask is not nomask:
-#                    newmask.shape = newdata.shape
-#        newdata = newdata.view(type(self))
-#        newdata._dates = newdates
-#        newdata._mask = newmask
-#        return newdata
-
-
-
     #........................
     def __setitem__(self, indx, value):
         """x.__setitem__(i, y) <==> x[i]=y
 Sets item described by index. If value is masked, masks those locations.
-        """
+"""
         if self is masked:
             raise MAError, 'Cannot alter the masked element.'
         (sindx, _) = self.__checkindex(indx)
@@ -472,9 +488,9 @@
         """Returns a string representation of self (w/o the dates...)"""
         return str(self._series)
     def __repr__(self):
-        """Calculates the repr representation, using masked for fill if
-           it is enabled. Otherwise fill with fill value.
-        """
+        """Calculates the repr representation, using masked for fill if it is
+enabled. Otherwise fill with fill value.
+"""
         desc = """\
 timeseries(
  %(data)s,
@@ -537,23 +553,14 @@
     stdu = _tsaxismethod('stdu')
     all = _tsaxismethod('all')
     any = _tsaxismethod('any')
-
-
-#    def nonzero(self):
-#        """Returns a tuple of ndarrays, one for each dimension of the array,
-#    containing the indices of the non-zero elements in that dimension."""
-#        return self._series.nonzero()
-
-#    filled = _tsarraymethod('filled', ondates=False)
-
-    #............................................
+    #.........................................................................
     def ids (self):
         """Return the ids of the data, dates and mask areas"""
         return (id(self._series), id(self.dates),)
-    #------------------------------------------------------
+    #.........................................................................
     @property
     def series(self):
-        "Returns the series."
+        """Returns the series."""
         return self._series
     @property
     def dates(self):
@@ -569,43 +576,43 @@
         return self._dates.freqstr
     @property
     def day(self):
-        "Returns the day of month for each date in self._dates."
+        """Returns the day of month for each date in self._dates."""
         return self._dates.day
     @property
     def day_of_week(self):
-        "Returns the day of week for each date in self._dates."
+        """Returns the day of week for each date in self._dates."""
         return self._dates.day_of_week
     @property
     def day_of_year(self):
-        "Returns the day of year for each date in self._dates."
+        """Returns the day of year for each date in self._dates."""
         return self._dates.day_of_year
     @property
     def month(self):
-        "Returns the month for each date in self._dates."
+        """Returns the month for each date in self._dates."""
         return self._dates.month
     @property
     def quarter(self):
-        "Returns the quarter for each date in self._dates."
+        """Returns the quarter for each date in self._dates."""
         return self._dates.quarter
     @property
     def year(self):
-        "Returns the year for each date in self._dates."
+        """Returns the year for each date in self._dates."""
         return self._dates.year
     @property
     def second(self):
-        "Returns the seconds for each date in self._dates."
+        """Returns the second for each date in self._dates."""
         return self._dates.second
     @property
     def minute(self):
-        "Returns the minutes for each date in self._dates."
+        """Returns the minute for each date in self._dates."""
         return self._dates.minute
     @property
     def hour(self):
-        "Returns the hour for each date in self._dates."
+        """Returns the hour for each date in self._dates."""
         return self._dates.hour
     @property
     def week(self):
-        "Returns the week for each date in self._dates."
+        """Returns the week for each date in self._dates."""
         return self._dates.week
 
     days = day
@@ -659,14 +666,33 @@
         return self._dates.has_duplicated_dates()
 
     def date_to_index(self, date):
-        "Returns the index corresponding to a given date, as an integer."
+        """Returns the index corresponding to a given date, as an integer."""
         return self._dates.date_to_index(date)
     #.....................................................
-    def asfreq(self, freq=None):
-        "Converts the dates to another frequency."
-        if freq is None:
-            return self
-        return TimeSeries(self._series, dates=self._dates.asfreq(freq))
+    def asfreq(self, freq, relation="AFTER"):
+        """Converts the dates portion of the TimeSeries to another frequency.
+
+The resulting TimeSeries will have the same shape and dimensions as the
+original series (unlike the `convert` method). 
+
+*Parameters*:
+    freq : {freq_spec}
+    relation : {'AFTER', 'BEFORE'} , optional
+
+*Returns*:
+    a new TimeSeries (data copied) with the .dates DateArray at the specified
+    frequency (the .asfreq method of the .dates property will be called)
+
+*Notes*:
+    The parameters are the exact same as for DateArray.asfreq , please see the
+    __doc__ string for that method for details on the parameters and how the
+    actual conversion is performed.
+"""
+        if freq is None: return self
+
+        return TimeSeries(self._series,
+                          dates=self._dates.asfreq(freq, relation=relation),
+                          copy=True)
     #.....................................................
     def transpose(self, *axes):
         """ a.transpose(*axes)
@@ -1193,7 +1219,7 @@
     
 
 #....................................................................
-def _convert1d(series, freq, func=None, position='END', *args, **kwargs):
+def _convert1d(series, freq, func, position, *args, **kwargs):
     "helper function for `convert` function"
     if not isinstance(series,TimeSeries):
         raise TypeError, "The argument should be a valid TimeSeries!"
@@ -1247,7 +1273,7 @@
     newseries.copy_attributes(series)
     return newseries
 
-def convert(series, freq, func='auto', position='END', *args, **kwargs):
+def convert(series, freq, func=None, position='END', *args, **kwargs):
     """Converts a series to a frequency. Private function called by convert
 
     When converting to a lower frequency, func is a function that acts
@@ -1280,6 +1306,7 @@
 
     return obj
 
+TimeSeries.convert = convert
 
 def group_byperiod(series, freq, position='END'):
     """Converts a series to a frequency, without any processing. If the series
@@ -1292,7 +1319,6 @@
         series = fill_missing_dates(series)
     return convert(series, freq, func=None, position=position)
 
-TimeSeries.convert = convert
 TimeSeries.group_byperiod = group_byperiod
 
 #...............................................................................



More information about the Scipy-svn mailing list