[Scipy-svn] r2633 - in trunk/Lib/sandbox/timeseries: . examples tests
scipy-svn at scipy.org
scipy-svn at scipy.org
Mon Jan 29 23:08:36 EST 2007
Author: pierregm
Date: 2007-01-29 22:08:29 -0600 (Mon, 29 Jan 2007)
New Revision: 2633
Modified:
trunk/Lib/sandbox/timeseries/.project
trunk/Lib/sandbox/timeseries/examples/example.py
trunk/Lib/sandbox/timeseries/examples/example.wiki
trunk/Lib/sandbox/timeseries/tcore.py
trunk/Lib/sandbox/timeseries/tdates.py
trunk/Lib/sandbox/timeseries/tests/test_dates.py
trunk/Lib/sandbox/timeseries/tests/test_misc.py
trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py
trunk/Lib/sandbox/timeseries/tests/test_timeseries.py
trunk/Lib/sandbox/timeseries/tmulti.py
trunk/Lib/sandbox/timeseries/tseries.py
Log:
fixed freq/freqstr
force DateArray singletons to shape (1,)
misc. improvements on tshift
Modified: trunk/Lib/sandbox/timeseries/.project
===================================================================
--- trunk/Lib/sandbox/timeseries/.project 2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/.project 2007-01-30 04:08:29 UTC (rev 2633)
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
- <name>timeseries</name>
+ <name>scipy_svn_timeseries</name>
<comment></comment>
<projects>
</projects>
Modified: trunk/Lib/sandbox/timeseries/examples/example.py
===================================================================
--- trunk/Lib/sandbox/timeseries/examples/example.py 2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/examples/example.py 2007-01-30 04:08:29 UTC (rev 2633)
@@ -14,15 +14,20 @@
TD.Date('D', mxDate=datetime.datetime.now())
mybirthday = D-1
infivemonths = M + 5
+mybirthday.asfreq('M')
+mybirthday.asfreq('M').asfreq('D')
data = N.random.uniform(-100,100,600)
today = TD.thisday('B')
series = TS.time_series(data, dtype=N.float_, freq='B', observed='SUMMED',
start_date=today-600)
+isinstance(series.dates, TD.DateArray)
+isinstance(series.series, MA.MaskedArray)
series[0]
series[-30:]
thirtydaysago = today - 30
series[thirtydaysago:]
series[thirtydaysago.tostring():]
+series[[0,-1]]
series[series<0] = 0
series[series.day_of_week == 4] = 100
weekdays = TD.day_of_week(series)
@@ -32,14 +37,14 @@
mlist_1 += ['2006-%02i' % i for i in range(2,13)]
mdata_1 = N.arange(len(mlist_1))
mser_1 = TS.time_series(mdata_1, mlist_1, observed='SUMMED')
-mser = mser1.asfreq('M')
-mser1.has_duplicated_dates()
-mser1.has_missing_dates()
+mser_1 = mser_1.asfreq('M')
+mser_1.has_duplicated_dates()
+mser_1.has_missing_dates()
mlist_2 = ['2004-%02i' % i for i in range(1,13)]
mlist_2 += ['2005-%02i' % i for i in range(1,13)]
mser_2 = TS.time_series(N.arange(len(mlist_2)), mlist_2, observed='SUMMED')
-mser_3 = mser_1 + mser_2
-(malg_1,malg_2) = aligned(mser_1, mser_2)
+#mser_3 = mser_1 + mser_2
+(malg_1,malg_2) = TS.aligned(mser_1, mser_2)
mser_1_filled = fill_missing_dates(mser_1)
(malg_1,malg_2) = align_series(mser_1_filled, mser_2)
mser_3 = malg_1 + malg_2
Modified: trunk/Lib/sandbox/timeseries/examples/example.wiki
===================================================================
--- trunk/Lib/sandbox/timeseries/examples/example.wiki 2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/examples/example.wiki 2007-01-30 04:08:29 UTC (rev 2633)
@@ -89,20 +89,26 @@
To construct a `DateArray` object, you can call the class directly
{{{#!python numbers=disable
+DateArray(dates=None, freq='U', copy=False)
}}}
+where `dates` can be ''(i)'' an existing `DateArray`; ''(ii)'' a sequence of `Date` objects; ''(iii)''' a sequence of objects that `Date` can recognize (such as strings, integers, `mx.DateTime` objects...).
+Alternatively, you can use the `date_array` constructor:
+{{{#!python numbers=disable
+date_array(dlist=None, start_date=None, end_date=None,
+ include_last=True, length=None, freq=None)
+}}}
+If `dlist` is None, a new list of dates will be created from `start_date` and `end_date`. You should set `include_last` to True if you want `end_date` to be included. If `end_date` is None, then a series of length `length` will be created.
-
----
== TimeSeries ==
A `TimeSeries` object is the combination of three ndarrays:
-
* `dates`: DateArray object.
* `data` : ndarray.
* `mask` : Boolean ndarray, indicating missing or invalid data.
-
+These three arrays can be accessed as attributes of a TimeSeries object. Another very useful attribute is `series`, that gives you the possibility to directly access `data` and `mask` as a masked array.
==== Construction ====
@@ -131,7 +137,16 @@
>>> series = TS.time_series(data, dtype=N.float_, freq='B', observed='SUMMED',
>>> start_date=today-600)
}}}
+We can check that `series.dates` is a `DateArray` object and that `series.series` is a `MaskedArray` object.
+{{{#!python numbers=disable
+>>> isinstance(series.dates, TD.DateArray)
+True
+>>> isinstance(series.series, MA.MaskedArray)
+True
+}}}
+So, if you are already familiar with `MaskedArray`, using `TimeSeries` should be straightforward. Just keep in mind that another attribute is always present, `dates`.
+
==== Indexing ====
Elements of a TimeSeries can be accessed just like with regular ndarrrays. Thus,
@@ -153,6 +168,11 @@
{{{#!python numbers=disable
>>> series[thirtydaysago.tostring():]
}}}
+or a sequence/ndarray of integers...
+{{{#!python numbers=disable
+>>> series[[0,-1]]
+}}}
+~-This latter is quite useful: it gives you the first and last data of your series.-~
In a similar way, setting elements of a TimeSeries works seamlessly.
Let us set negative values to zero...
@@ -190,16 +210,20 @@
}}}
Note that the frequency is 'U', for undefined. In fact, you have to specify what kind of data is actually missing by forcing a given frequency.
{{{#!python numbers=disable
->>> mser = mser1.asfreq('M')
+>>> mser = mser_1.asfreq('M')
}}}
Let us check whether there are some duplicated dates (no):
{{{#!python numbers=disable
->>> mser1.has_duplicated_dates()
+>>> mser_1.has_duplicated_dates()
+False
}}}
...or missing dates (yes):
{{{#!python numbers=disable
->>> mser1.has_missing_dates()
+>>> mser_1.has_missing_dates()
+True
}}}
+
+
Let us construct a second monthly series, this time without missing dates
{{{#!python numbers=disable
>>> mlist_2 = ['2004-%02i' % i for i in range(1,13)]
@@ -227,7 +251,7 @@
{{{#!python numbers=disable
>>> mser_3 = filled(malg_1,0) + filled(malg_2,0)
}}}
-Alternatively, we can force the series to start/end at some given dates
+When aligning the series, we could have forced the series to start/end at some given dates:
{{{#!python numbers=disable
>>> (malg_1,malg_2) = aligned(mser_1_filled, mser2,
>>> start_date='2004-06', end_date='2006-06')
Modified: trunk/Lib/sandbox/timeseries/tcore.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tcore.py 2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tcore.py 2007-01-30 04:08:29 UTC (rev 2633)
@@ -81,87 +81,114 @@
raise ValueError("Invalid value for observed attribute: %s " % str(obStr))
-fmtfreq_dict = {'A': ['ANNUAL','ANNUALLY','YEAR','YEARLY'],
- 'B': ['BUSINESS','BUSINESSLYT'],
- 'D': ['DAY','DAILY',],
- 'H': ['HOUR','HOURLY',],
- 'M': ['MONTH','MONTHLY',],
- 'Q': ['QUARTER','QUARTERLY',],
- 'S': ['SECOND','SECONDLY',],
- 'T': ['MINUTE','MINUTELY',],
- 'W': ['WEEK','WEEKLY',],
- 'U': ['UNDEF','UNDEFINED'],
+
+freq_dict = { 1000: ['A','Y','ANNUAL','ANNUALLY','YEAR','YEARLY'],
+ 2000: ['Q','QUARTER','QUARTERLY',],
+ 3000: ['M','MONTH','MONTHLY',],
+ 4000: ['W','WEEK','WEEKLY',],
+ 5000: ['B','BUSINESS','BUSINESSLYT'],
+ 6000: ['D','DAY','DAILY',],
+ 7000: ['H','HOUR','HOURLY',],
+ 8000: ['T','MINUTE','MINUTELY',],
+ 9000: ['S','SECOND','SECONDLY',],
+ -9999: ['U','UNDEF','UNDEFINED'],
}
-fmtfreq_revdict = reverse_dict(fmtfreq_dict)
+freq_revdict = reverse_dict(freq_dict)
-def fmtFreq (freqStr):
+def freq_fromstr(freq_asstr):
+ "Converts a frequency given as string to the corresponding integer."
+ freq_asstr = freq_asstr.upper()
+ if freq_asstr not in freq_revdict.keys():
+ raise ValueError, "Invalid frequency string %s" % freq_asstr
+ return freq_revdict[freq_asstr]
+
+def freq_tostr(freq_asint):
+ "Converts a frequency given as integer to the corresponding symbol."
+ if freq_asint not in freq_dict.keys():
+ raise ValueError, "Invalid frequency representation %s" % freq_asint
+ return freq_dict[freq_asint][0]
+
+def check_freq(freq):
"Converts a possible 'frequency' string to acceptable values."
- if freqStr is None:
- return None
- elif freqStr.upper() in fmtfreq_dict.keys():
- return freqStr[0].upper()
- elif freqStr.upper() in fmtfreq_revdict.keys():
- return fmtfreq_revdict[freqStr.upper()]
+ if freq is None:
+ return None
+ elif isinstance(freq, int):
+ if freq not in freq_dict.keys():
+ raise ValueError("Invalid frequency: %s " % str(freq))
+ return freq
+ elif freq.upper() in freq_revdict.keys():
+ return freq_revdict[freq.upper()]
else:
- raise ValueError("Invalid frequency: %s " % str(freqStr))
-
-class DateSpec:
- "Fake data type for date variables."
- def __init__(self, freq):
- self.freq = fmtFreq(freq)
-
- def __hash__(self):
- return hash(self.freq)
+ raise ValueError("Invalid frequency: %s " % str(freq))
- def __eq__(self, other):
- if hasattr(other, "freq"):
- return self.freq == other.freq
- else:
- return False
- def __str__(self):
- return "Date(%s)" % str(self.freq)
-
-
-
-# define custom numpy types.
-# Note: A more robust approach would register these as actual valid numpy types
-# this is just a hack for now
-numpy.dateA = DateSpec("Annual")
-numpy.dateB = DateSpec("Business")
-numpy.dateD = DateSpec("Daily")
-numpy.dateH = DateSpec("Hourly")
-numpy.dateM = DateSpec("Monthly")
-numpy.dateQ = DateSpec("Quarterly")
-numpy.dateS = DateSpec("Secondly")
-numpy.dateT = DateSpec("Minutely")
-numpy.dateW = DateSpec("Weekly")
-numpy.dateU = DateSpec("Undefined")
-
-
-freq_type_mapping = {'A': numpy.dateA,
- 'B': numpy.dateB,
- 'D': numpy.dateD,
- 'H': numpy.dateH,
- 'M': numpy.dateM,
- 'Q': numpy.dateQ,
- 'S': numpy.dateS,
- 'T': numpy.dateT,
- 'W': numpy.dateW,
- 'U': numpy.dateU,
- }
+def check_freqstr(freq):
+ if freq is None:
+ return None
+ elif isinstance(freq, int):
+ if freq not in freq_dict.keys():
+ raise ValueError("Invalid frequency: %s " % str(freq))
+ return freq_dict[freq][0]
+ elif freq.upper() in freq_revdict.keys():
+ return freq_dict[freq_revdict[freq.upper()]][0]
+ else:
+ raise ValueError("Invalid frequency: %s " % str(freq))
+fmtFreq = check_freqstr
-def freqToType(freq):
- "Returns the Date dtype corresponding to the given frequency."
- return freq_type_mapping[fmtFreq(freq)]
+#class DateSpec:
+# "Fake data type for date variables."
+# def __init__(self, freq):
+# self.freq = fmtFreq(freq)
+#
+# def __hash__(self):
+# return hash(self.freq)
+#
+# def __eq__(self, other):
+# if hasattr(other, "freq"):
+# return self.freq == other.freq
+# else:
+# return False
+# def __str__(self):
+# return "Date(%s)" % str(self.freq)
+#
+## define custom numpy types.
+## Note: A more robust approach would register these as actual valid numpy types
+## this is just a hack for now
+#numpy.dateA = DateSpec("Annual")
+#numpy.dateB = DateSpec("Business")
+#numpy.dateD = DateSpec("Daily")
+#numpy.dateH = DateSpec("Hourly")
+#numpy.dateM = DateSpec("Monthly")
+#numpy.dateQ = DateSpec("Quarterly")
+#numpy.dateS = DateSpec("Secondly")
+#numpy.dateT = DateSpec("Minutely")
+#numpy.dateW = DateSpec("Weekly")
+#numpy.dateU = DateSpec("Undefined")
+#
+#
+#freq_type_mapping = {'A': numpy.dateA,
+# 'B': numpy.dateB,
+# 'D': numpy.dateD,
+# 'H': numpy.dateH,
+# 'M': numpy.dateM,
+# 'Q': numpy.dateQ,
+# 'S': numpy.dateS,
+# 'T': numpy.dateT,
+# 'W': numpy.dateW,
+# 'U': numpy.dateU,
+# }
+#
+#def freqToType(freq):
+# "Returns the Date dtype corresponding to the given frequency."
+# return freq_type_mapping[fmtFreq(freq)]
+#
+#def isDateType(dtype):
+# "Returns True whether the argument is the dtype of a Date."
+# #TODO: That looks messy. We should simplify that
+# if len([x for x in freq_type_mapping.values() if x == dtype]) > 0:
+# return True
+# else:
+# return False
-def isDateType(dtype):
- "Returns True whether the argument is the dtype of a Date."
- #TODO: That looks messy. We should simplify that
- if len([x for x in freq_type_mapping.values() if x == dtype]) > 0:
- return True
- else:
- return False
-
#####---------------------------------------------------------------------------
#---- --- Misc functions ---
#####---------------------------------------------------------------------------
Modified: trunk/Lib/sandbox/timeseries/tdates.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tdates.py 2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tdates.py 2007-01-30 04:08:29 UTC (rev 2633)
@@ -32,10 +32,6 @@
import cseries
-import logging
-logging.basicConfig(level=logging.DEBUG,format='%(name)-15s %(levelname)s %(message)s',)
-daflog = logging.getLogger('darray_from')
-dalog = logging.getLogger('DateArray')
__all__ = [
@@ -116,38 +112,54 @@
>>> td.Date('D', mxDate=mx.DateTime.now())
>>> td.Date('D', mxDate=datetime.datetime.now())
"""
- def __init__(self, freq, year=None, month=None, day=None, quarter=None,
+ default_fmtstr = {'A': "%Y",
+ 'Q': "%YQ%q",
+ 'M': "%b-%Y",
+ 'W': "%d-%b-%y",
+ 'B': "%d-%b-%Y",
+ 'D': "%d-%b-%Y",
+ 'U': "%d-%b-%Y",
+ 'H': "%d-%b-%Y %H:00",
+ 'T': "%d-%b-%Y %H:%M",
+ 'S': "%d-%b-%Y %H:%M:%S"
+ }
+
+ def __init__(self, freq, value=None, string=None,
+ year=None, month=None, day=None, quarter=None,
hour=None, minute=None, second=None,
- mxDate=None, value=None, string=None):
+ mxDate=None):
if hasattr(freq, 'freq'):
- self.freq = corelib.fmtFreq(freq.freq)
+ self.freq = corelib.check_freq(freq.freq)
else:
- self.freq = corelib.fmtFreq(freq)
- self.freqstr = self.freq
+ self.freq = corelib.check_freq(freq)
+ self.freqstr = corelib.freq_tostr(self.freq)
if value is not None:
- if self.freq == 'A':
+ if isinstance(value, str):
+ self.mxDate = mxDFromString(string)
+ elif self.freqstr == 'A':
self.mxDate = mxD.Date(value, -1, -1)
- elif self.freq == 'B':
+ elif self.freqstr == 'B':
valtmp = (value - 1)//5
- self.mxDate = mxD.DateTimeFromAbsDateTime(value + valtmp*7 - valtmp*5)
- elif self.freq in ['D','U']:
+ #... (value + valtmp*7 - valtmp*5)
+ self.mxDate = mxD.DateTimeFromAbsDateTime(value + valtmp*2)
+ elif self.freqstr in ['D','U']:
self.mxDate = mxD.DateTimeFromAbsDateTime(value)
- elif self.freq == 'H':
+ elif self.freqstr == 'H':
self.mxDate = hourlyOriginDate + mxD.DateTimeDeltaFrom(hours=value)
- elif self.freq == 'M':
+ elif self.freqstr == 'M':
self.mxDate = mxD.DateTimeFromAbsDateTime(1) + \
mxD.RelativeDateTime(months=value-1, day=-1)
- elif self.freq == 'Q':
+ elif self.freqstr == 'Q':
self.mxDate = mxD.DateTimeFromAbsDateTime(1) + \
mxD.RelativeDateTime(years=(value // 4),
month=((value * 3) % 12), day=-1)
- elif self.freq == 'S':
+ elif self.freqstr == 'S':
self.mxDate = secondlyOriginDate + mxD.DateTimeDeltaFromSeconds(value)
- elif self.freq == 'T':
+ elif self.freqstr == 'T':
self.mxDate = minutelyOriginDate + mxD.DateTimeDeltaFrom(minutes=value)
- elif self.freq == 'W':
+ elif self.freqstr == 'W':
self.mxDate = mxD.Date(1,1,7) + \
mxD.RelativeDateTime(weeks=value-1)
@@ -163,31 +175,31 @@
# First, some basic checks.....
if year is None:
raise InsufficientDateError
- if self.freq in ('B', 'D', 'W'):
+ if self.freqstr in 'BDWU':
if month is None or day is None:
raise InsufficientDateError
- elif self.freq == 'M':
+ elif self.freqstr == 'M':
if month is None:
raise InsufficientDateError
day = -1
- elif self.freq == 'Q':
+ elif self.freqstr == 'Q':
if quarter is None:
raise InsufficientDateError
month = quarter * 3
day = -1
- elif self.freq == 'A':
+ elif self.freqstr == 'A':
month = -1
day = -1
- elif self.freq == 'S':
+ elif self.freqstr == 'S':
if month is None or day is None or second is None:
raise InsufficientDateError
- if self.freq in ['A','B','D','M','Q','W']:
+ if self.freqstr in ['A','B','D','M','Q','W']:
self.mxDate = truncateDate(self.freq, mxD.Date(year, month, day))
- if self.freq == 'B':
+ if self.freqstr == 'B':
if self.mxDate.day_of_week in [5,6]:
raise ValueError("Weekend passed as business day")
- elif self.freq in ['H','S','T']:
+ elif self.freqstr in 'HTS':
if hour is None:
if minute is None:
if second is None:
@@ -205,7 +217,7 @@
second = 0
else:
second = second % 60
- self.mxDate = truncateDate(self.freq,
+ self.mxDate = truncateDate(self.freqstr,
mxD.Date(year, month, day,
hour, minute, second))
self.value = self.__value()
@@ -252,11 +264,13 @@
return self.__getDateInfo('I')
def __getDateInfo(self, info):
- return int(cseries.getDateInfo(numpy.asarray(self.value), self.freq, info))
+ return int(cseries.getDateInfo(numpy.asarray(self.value),
+ self.freqstr, info))
def __add__(self, other):
if isinstance(other, Date):
- raise FrequencyDateError("Cannot add dates", self.freq, other.freq)
+ raise FrequencyDateError("Cannot add dates",
+ self.freqstr, other.freqstr)
return Date(freq=self.freq, value=int(self) + other)
def __radd__(self, other):
@@ -266,7 +280,7 @@
if isinstance(other, Date):
if self.freq != other.freq:
raise FrequencyDateError("Cannot subtract dates", \
- self.freq, other.freq)
+ self.freqstr, other.freqstr)
else:
return int(self) - int(other)
else:
@@ -276,16 +290,16 @@
if not hasattr(other, 'freq'):
return False
elif self.freq != other.freq:
- raise FrequencyDateError("Cannot subtract dates", \
- self.freq, other.freq)
+ raise FrequencyDateError("Cannot compare dates", \
+ self.freqstr, other.freqstr)
return int(self) == int(other)
def __cmp__(self, other):
if not hasattr(other, 'freq'):
return False
elif self.freq != other.freq:
- raise FrequencyDateError("Cannot subtract dates", \
- self.freq, other.freq)
+ raise FrequencyDateError("Cannot compare dates", \
+ self.freqstr, other.freqstr)
return int(self)-int(other)
def __hash__(self):
@@ -300,63 +314,41 @@
def __value(self):
"Converts the date to an integer, depending on the current frequency."
# Annual .......
- if self.freq == 'A':
+ if self.freqstr == 'A':
val = self.mxDate.year
# Business days.
- elif self.freq == 'B':
+ elif self.freqstr == 'B':
days = self.mxDate.absdate
weeks = days // 7
val = days - weeks*2
# (weeks*5) + (days - weeks*7)
# Daily/undefined
- elif self.freq in ['D', 'U']:
+ elif self.freqstr in 'DU':
val = self.mxDate.absdate
# Hourly........
- elif self.freq == 'H':
+ elif self.freqstr == 'H':
val = (self.mxDate - hourlyOriginDate).hours
# Monthly.......
- elif self.freq == 'M':
+ elif self.freqstr == 'M':
val = (self.mxDate.year-1)*12 + self.mxDate.month
# Quarterly.....
- elif self.freq == 'Q':
+ elif self.freqstr == 'Q':
val = (self.mxDate.year-1)*4 + self.mxDate.month//3
# Secondly......
- elif self.freq == 'S':
+ elif self.freqstr == 'S':
val = (self.mxDate - secondlyOriginDate).seconds
# Minutely......
- elif self.freq == 'T':
+ elif self.freqstr == 'T':
val = (self.mxDate - minutelyOriginDate).minutes
# Weekly........
- elif self.freq == 'W':
+ elif self.freqstr == 'W':
val = self.mxDate.absdate//7
return int(val)
- #......................................................
- def default_fmtstr(self):
- "Defines the default formats for printing Dates."
- if self.freq == "A":
- fmt = "%Y"
- elif self.freq in ("B","D"):
- fmt = "%d-%b-%Y"
- elif self.freq == "M":
- fmt = "%b-%Y"
- elif self.freq == "Q":
- fmt = "%YQ%q"
- elif self.freq == 'H':
- fmt = "%d-%b-%Y %H:00"
- elif self.freq == 'T':
- fmt = "%d-%b-%Y %H:%M"
- elif self.freq == "S":
- fmt = "%d-%b-%Y %H:%M:%S"
- elif self.freq == "W":
- fmt = "%YW%W"
- else:
- fmt = "%d-%b-%y"
- return fmt
-
+ #......................................................
def strfmt(self, fmt):
"Formats the date"
if fmt is None:
- fmt = self.default_fmtstr()
+ fmt = self.default_fmtstr[self.freqstr]
qFmt = fmt.replace("%q", "XXXX")
tmpStr = self.mxDate.strftime(qFmt)
if "XXXX" in tmpStr:
@@ -364,10 +356,10 @@
return tmpStr
def __str__(self):
- return self.strfmt(self.default_fmtstr())
+ return self.strfmt(self.default_fmtstr[self.freqstr])
def __repr__(self):
- return "<%s : %s>" % (str(self.freq), str(self))
+ return "<%s : %s>" % (str(self.freqstr), str(self))
#......................................................
def toordinal(self):
"Returns the date as an ordinal."
@@ -400,24 +392,24 @@
#####---------------------------------------------------------------------------
def truncateDate(freq, mxDate):
"""Chops off the irrelevant information from the mxDate passed in."""
- freq = corelib.fmtFreq(freq)
- if freq == 'A':
+ freqstr = corelib.check_freqstr(freq)
+ if freqstr == 'A':
return mxD.Date(mxDate.year)
- elif freq == 'Q':
+ elif freqstr == 'Q':
return mxD.Date(mxDate.year, monthToQuarter(mxDate.month)*3)
- elif freq == 'M':
+ elif freqstr == 'M':
return mxD.Date(mxDate.year, mxDate.month)
- elif freq == 'W':
+ elif freqstr == 'W':
d = mxDate.absdate
return mxD.DateTimeFromAbsDateTime(d + (7 - d % 7) % 7)
- elif freq in ('B', 'D'):
+ elif freqstr in 'BD':
if freq == 'B' and mxDate.day_of_week in [5,6]:
raise ValueError("Weekend passed as business day")
return mxD.Date(mxDate.year, mxDate.month, mxDate.day)
- elif freq == 'H':
+ elif freqstr == 'H':
return mxD.Date(mxDate.year, mxDate.month, mxDate.day, \
mxDate.hour)
- elif freq == 'T':
+ elif freqstr == 'T':
return mxD.Date(mxDate.year, mxDate.month, mxDate.day, \
mxDate.hour, mxDate.minute)
else:
@@ -430,18 +422,18 @@
def thisday(freq):
"Returns today's date, at the given frequency `freq`."
- freq = corelib.fmtFreq(freq)
+ freqstr = corelib.check_freqstr(freq)
tempDate = mxD.now()
# if it is Saturday or Sunday currently, freq==B, then we want to use Friday
- if freq == 'B' and tempDate.day_of_week >= 5:
+ if freqstr == 'B' and tempDate.day_of_week >= 5:
tempDate -= (tempDate.day_of_week - 4)
- if freq in ('B','D','H','S','T','W'):
+ if freqstr in ('B','D','H','S','T','W','U'):
return Date(freq, mxDate=tempDate)
- elif freq == 'M':
+ elif freqstr == 'M':
return Date(freq, year=tempDate.year, month=tempDate.month)
- elif freq == 'Q':
+ elif freqstr == 'Q':
return Date(freq, year=tempDate.year, quarter=monthToQuarter(tempDate.month))
- elif freq == 'A':
+ elif freqstr == 'A':
return Date(freq, year=tempDate.year)
today = thisday
@@ -458,7 +450,7 @@
def asfreq(date, toFreq, relation="BEFORE"):
"""Returns a date converted to another frequency `toFreq`, according to the
relation `relation` ."""
- tofreq = corelib.fmtFreq(toFreq)
+ tofreq = corelib.check_freqstr(toFreq)
_rel = relation.upper()[0]
if _rel not in ['B', 'A']:
msg = "Invalid relation '%s': Should be in ['before', 'after']"
@@ -467,11 +459,11 @@
if not isinstance(date, Date):
raise DateError, "Date should be a valid Date instance!"
- if date.freq == 'U':
+ if date.freqstr == 'U':
warnings.warn("Undefined frequency: assuming daily!")
fromfreq = 'D'
else:
- fromfreq = date.freq
+ fromfreq = date.freqstr
if fromfreq == tofreq:
return date
@@ -507,21 +499,20 @@
accesses the array element by element. Therefore, `d` is a Date object.
"""
def __new__(cls, dates=None, freq='U', copy=False):
- #logging.debug('DA:__new__ received %s [%i]" % (type(dates), numpy.size(dates)))
if isinstance(dates, DateArray):
- #logging.debug('DA:__new__ sends %s as %s" % (type(dates), cls))
cls.__defaultfreq = dates.freq
if not copy:
return dates.view(cls)
return dates.copy().view(cls)
else:
_dates = numeric.asarray(dates, dtype=int_)
+ if _dates.ndim == 0:
+ _dates.shape = (1,)
if copy:
_dates = _dates.copy()
- #logging.debug('DA:__new__ sends %s as %s" % (type(_dates), cls))
if freq is None:
freq = 'U'
- cls.__defaultfreq = corelib.fmtFreq(freq)
+ cls.__defaultfreq = corelib.check_freq(freq)
(cls.__toobj, cls.__toord, cls.__tostr) = (None, None, None)
(cls.__steps, cls.__full, cls.__hasdups) = (None, None, None)
return _dates.view(cls)
@@ -533,25 +524,22 @@
raise ArithmeticDateError, "(function %s)" % context[0].__name__
def __array_finalize__(self, obj):
- #logging.debug('DA:__array_finalize__ received %s" % type(obj))
if hasattr(obj, 'freq'):
self.freq = obj.freq
self.freqstr = obj.freqstr
else:
self.freq = self.__defaultfreq
- self.freqstr = self.__defaultfreq
- #logging.debug('DA:__array_finalize__ sends %s" % type(self))
+ self.freqstr = corelib.freq_tostr(self.__defaultfreq)
- def __getitem__(self, index):
- #logging.debug('DA:__getitem__ got index %s (%s)"%(index, type(index)))
- if isinstance(index, Date):
- index = self.find_dates(index)
- elif numeric.asarray(index).dtype.kind == 'O':
+ def __getitem__(self, indx):
+ if isinstance(indx, Date):
+ index = self.find_dates(indx)
+ elif numeric.asarray(indx).dtype.kind == 'O':
try:
- index = self.find_dates(index)
+ indx = self.find_dates(indx)
except AttributeError:
pass
- r = ndarray.__getitem__(self, index)
+ r = ndarray.__getitem__(self, indx)
if not hasattr(r, "size"):
if isinstance(r, int):
return Date(self.freq, value=r)
@@ -661,7 +649,7 @@
tofreq = corelib.fmtFreq(freq)
if tofreq == self.freq:
return self
- if self.freq == 'U':
+ if self.freqstr == 'U':
warnings.warn("Undefined frequency: assuming daily!")
fromfreq = 'D'
else:
@@ -709,14 +697,15 @@
self.__full = (steps.max() == 1)
if self.__hasdups is None:
self.__hasdups = (steps.min() == 0)
- elif val.size == 1:
+ else:
+# elif val.size == 1:
self.__full = True
self.__hasdups = False
steps = numeric.array([], dtype=int_)
- else:
- self.__full = False
- self.__hasdups = False
- steps = None
+# else:
+# self.__full = False
+# self.__hasdups = False
+# steps = None
self.__steps = steps
return self.__steps
@@ -758,7 +747,6 @@
self._asdates = asdates
self.__doc__ = getattr(methodname, '__doc__')
self.obj = None
- #logging.debug('DA:__datearithmetics got method %s' % methodname)
#
def __get__(self, obj, objtype=None):
self.obj = obj
@@ -770,7 +758,6 @@
freq = instance.freq
if 'context' not in kwargs:
kwargs['context'] = 'DateOK'
- #logging.debug('DA:__datearithmetics got other %s' % type(other))
method = getattr(super(DateArray,instance), self.methodname)
if isinstance(other, DateArray):
if other.freq != freq:
@@ -782,7 +769,6 @@
raise FrequencyDateError("Cannot operate on dates", \
freq, other.freq)
other = other.value
- #logging.debug('DA:__datearithmetics got other %s' % type(other))
elif isinstance(other, ndarray):
if other.dtype.kind not in ['i','f']:
raise ArithmeticDateError
@@ -848,6 +834,8 @@
"Constructs a DateArray from a list."
dlist = numeric.asarray(dlist)
dlist.sort()
+ if dlist.ndim == 0:
+ dlist.shape = (1,)
# Case #1: dates as strings .................
if dlist.dtype.kind == 'S':
#...construct a list of ordinals
@@ -860,7 +848,7 @@
#...construct a list of dates
dates = [Date(freq, string=s) for s in dlist]
# Case #2: dates as numbers .................
- elif dlist.dtype.kind in ['i','f']:
+ elif dlist.dtype.kind in 'if':
#...hopefully, they are values
if freq is None:
freq = guess_freq(dlist)
@@ -868,9 +856,17 @@
# Case #3: dates as objects .................
elif dlist.dtype.kind == 'O':
template = dlist[0]
+# if dlist.size > 1:
+# template = dlist[0]
+# else:
+# template = dlist.item()
#...as Date objects
if isinstance(template, Date):
- dates = numpy.fromiter((d.value for d in dlist), float_)
+ dates = numpy.fromiter((d.value for d in dlist), int_)
+# if dlist.size > 1:
+# dates = numpy.fromiter((d.value for d in dlist), int_)
+# else:
+# dates = [template]
#...as mx.DateTime objects
elif hasattr(template,'absdays'):
# no freq given: try to guess it from absdays
@@ -880,7 +876,7 @@
freq = guess_freq(ords)
dates = [Date(freq, mxDate=m) for m in dlist]
#...as datetime objects
- elif hasattr(dlist[0], 'toordinal'):
+ elif hasattr(template, 'toordinal'):
ords = numpy.fromiter((d.toordinal() for d in dlist), float_)
if freq is None:
freq = guess_freq(ords)
@@ -896,8 +892,7 @@
- a starting date and either an ending date or a given length.
- a list of dates.
"""
- #TODO: make sure we can use a string for a date!
- freq = corelib.fmtFreq(freq)
+ freq = corelib.check_freq(freq)
# Case #1: we have a list ...................
if dlist is not None:
# Already a DateArray....................
Modified: trunk/Lib/sandbox/timeseries/tests/test_dates.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tests/test_dates.py 2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tests/test_dates.py 2007-01-30 04:08:29 UTC (rev 2633)
@@ -26,8 +26,9 @@
from maskedarray.testutils import assert_equal, assert_array_equal
from timeseries import tdates
+reload(tdates)
from timeseries import tcore
-reload(tdates)
+reload(tcore)
from timeseries.tdates import date_array_fromlist, Date, DateArray, mxDFromString
class test_creation(NumpyTestCase):
@@ -41,33 +42,33 @@
dlist = ['2007-01-%02i' % i for i in range(1,15)]
# A simple case: daily data
dates = date_array_fromlist(dlist, 'D')
- assert_equal(dates.freq,'D')
+ assert_equal(dates.freqstr,'D')
assert(dates.isfull())
assert(not dates.has_duplicated_dates())
assert_equal(dates, 732677+numpy.arange(len(dlist)))
# as simple, but we need to guess the frequency this time
dates = date_array_fromlist(dlist, 'D')
- assert_equal(dates.freq,'D')
+ assert_equal(dates.freqstr,'D')
assert(dates.isfull())
assert(not dates.has_duplicated_dates())
assert_equal(dates, 732677+numpy.arange(len(dlist)))
# Still daily data, that we force to month
dates = date_array_fromlist(dlist, 'M')
- assert_equal(dates.freq,'M')
+ assert_equal(dates.freqstr,'M')
assert(not dates.isfull())
assert(dates.has_duplicated_dates())
assert_equal(dates, [24073]*len(dlist))
# Now, for monthly data
dlist = ['2007-%02i' % i for i in range(1,13)]
dates = date_array_fromlist(dlist, 'M')
- assert_equal(dates.freq,'M')
+ assert_equal(dates.freqstr,'M')
assert(dates.isfull())
assert(not dates.has_duplicated_dates())
assert_equal(dates, 24073 + numpy.arange(12))
# Monthly data w/ guessing
dlist = ['2007-%02i' % i for i in range(1,13)]
dates = date_array_fromlist(dlist, )
- assert_equal(dates.freq,'M')
+ assert_equal(dates.freqstr,'M')
assert(dates.isfull())
assert(not dates.has_duplicated_dates())
assert_equal(dates, 24073 + numpy.arange(12))
@@ -76,18 +77,18 @@
"Tests creation from list of strings w/ missing dates"
dlist = ['2007-01-%02i' % i for i in (1,2,4,5,7,8,10,11,13)]
dates = date_array_fromlist(dlist)
- assert_equal(dates.freq,'U')
+ assert_equal(dates.freqstr,'U')
assert(not dates.isfull())
assert(not dates.has_duplicated_dates())
assert_equal(dates.tovalue(),732676+numpy.array([1,2,4,5,7,8,10,11,13]))
#
ddates = date_array_fromlist(dlist, 'D')
- assert_equal(ddates.freq,'D')
+ assert_equal(ddates.freqstr,'D')
assert(not ddates.isfull())
assert(not ddates.has_duplicated_dates())
#
mdates = date_array_fromlist(dlist, 'M')
- assert_equal(mdates.freq,'M')
+ assert_equal(mdates.freqstr,'M')
assert(not dates.isfull())
assert(mdates.has_duplicated_dates())
#
@@ -105,7 +106,8 @@
def test_consistent_value(self):
"Tests that values don't get mutated when constructing dates from a value"
- freqs = [x for x in list(tcore.fmtfreq_dict) if x != 'U']
+ freqs = [x[0] for x in tcore.freq_dict.values() if x[0] != 'U']
+ print freqs
for f in freqs:
today = tdates.thisday(f)
assert(tdates.Date(freq=f, value=today.value) == today)
Modified: trunk/Lib/sandbox/timeseries/tests/test_misc.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tests/test_misc.py 2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tests/test_misc.py 2007-01-30 04:08:29 UTC (rev 2633)
@@ -2,11 +2,11 @@
"""Tests suite for miscellaneous functions in timeseries module.
Adapted from the original test_ma by Pierre Gerard-Marchant
-:author: Matt Knox
-:contact: mattknox_ca_at_hotmail_dot_com
-:version: $Id: test_misc.py 2578 2007-01-17 19:25:10Z mattknox_ca $
+:author: Pierre Gerard-Marchant & Matt Knox
+:contact: pierregm_at_uga_dot_edu & mattknox_ca_at_hotmail_dot_com
+:version: $Id: test_timeseries.py 2578 2007-01-17 19:25:10Z mattknox_ca $
"""
-__author__ = "Matt Knox ($Author: mattknox_ca $)"
+__author__ = "Pierre GF Gerard-Marchant & Matt Knox ($Author: mattknox_ca $)"
__version__ = '1.0'
__revision__ = "$Revision: 2578 $"
__date__ = '$Date: 2007-01-17 14:25:10 -0500 (Wed, 17 Jan 2007) $'
Modified: trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py 2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tests/test_multitimeseries.py 2007-01-30 04:08:29 UTC (rev 2633)
@@ -1,11 +1,11 @@
# pylint: disable-msg=W0611, W0612, W0511,R0201
"""Tests suite for mrecarray.
-:author: Pierre Gerard-Marchant
-:contact: pierregm_at_uga_dot_edu
+:author: Pierre Gerard-Marchant & Matt Knox
+:contact: pierregm_at_uga_dot_edu & mattknox_ca_at_hotmail_dot_com
:version: $Id$
"""
-__author__ = "Pierre GF Gerard-Marchant ($Author$)"
+__author__ = "Pierre GF Gerard-Marchant & Matt Knox ($Author$)"
__version__ = '1.0'
__revision__ = "$Revision$"
__date__ = '$Date$'
Modified: trunk/Lib/sandbox/timeseries/tests/test_timeseries.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tests/test_timeseries.py 2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tests/test_timeseries.py 2007-01-30 04:08:29 UTC (rev 2633)
@@ -2,11 +2,11 @@
"""Tests suite for MaskedArray.
Adapted from the original test_ma by Pierre Gerard-Marchant
-:author: Pierre Gerard-Marchant
-:contact: pierregm_at_uga_dot_edu
+:author: Pierre Gerard-Marchant & Matt Knox
+:contact: pierregm_at_uga_dot_edu & mattknox_ca_at_hotmail_dot_com
:version: $Id$
"""
-__author__ = "Pierre GF Gerard-Marchant ($Author$)"
+__author__ = "Pierre GF Gerard-Marchant & Matt Knox ($Author$)"
__version__ = '1.0'
__revision__ = "$Revision$"
__date__ = '$Date$'
@@ -28,7 +28,8 @@
from timeseries import tseries
#reload(tseries)
from timeseries.tseries import Date, date_array_fromlist
-from timeseries.tseries import time_series, TimeSeries, adjust_endpoints, mask_period, align_series
+from timeseries.tseries import time_series, TimeSeries, adjust_endpoints, \
+ mask_period, align_series
class test_creation(NumpyTestCase):
"Base test class for MaskedArrays."
@@ -47,7 +48,7 @@
assert_equal(series._mask, [1,0,0,0,0]*3)
assert_equal(series._series, data)
assert_equal(series._dates, date_array_fromlist(dlist))
- assert_equal(series.freq, 'D')
+ assert_equal(series.freqstr, 'D')
def test_fromrange (self):
"Base data definition."
@@ -57,7 +58,7 @@
assert_equal(series._mask, [1,0,0,0,0]*3)
assert_equal(series._series, data)
assert_equal(series._dates, dates)
- assert_equal(series.freq, 'D')
+ assert_equal(series.freqstr, 'D')
def test_fromseries (self):
"Base data definition."
@@ -69,7 +70,7 @@
assert_equal(series._mask, [1,0,0,0,0]*3)
assert_equal(series._series, data)
assert_equal(series._dates, dates)
- assert_equal(series.freq, 'D')
+ assert_equal(series.freqstr, 'D')
def test_fromdatearray(self):
@@ -81,7 +82,7 @@
assert(isinstance(series, TimeSeries))
assert_equal(series._dates, dates)
assert_equal(series._data, data)
- assert_equal(series.freq, 'D')
+ assert_equal(series.freqstr, 'D')
series[5] = MA.masked
@@ -270,12 +271,12 @@
end_date=Date('D', string='2007-01-31'))
assert_equal(dseries.size, 26)
assert_equal(dseries._mask, N.r_[series._mask[5:], [1]*16])
-
+ #
empty_series = time_series([], freq='d')
a, b = align_series(series, empty_series)
assert_equal(a.start_date, b.start_date)
assert_equal(a.end_date, b.end_date)
-
+ #
def test_tshift(self):
"Test tshift function"
series = self.d[0]
@@ -291,7 +292,6 @@
assert_array_equal(shift_negative, shift_negative_result)
assert_array_equal(shift_positive, shift_positive_result)
-
#
def test_maskperiod(self):
"Test mask_period"
Modified: trunk/Lib/sandbox/timeseries/tmulti.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tmulti.py 2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tmulti.py 2007-01-30 04:08:29 UTC (rev 2633)
@@ -51,8 +51,6 @@
reserved_fields = MR.reserved_fields + ['_dates']
import warnings
-import logging
-logging.basicConfig(level=logging.DEBUG,
format='%(name)-15s %(levelname)s %(message)s',)
__all__ = [
@@ -103,7 +101,6 @@
mroptions = dict(fill_value=fill_value, hard_mask=hard_mask,
formats=formats, names=names, titles=titles,
byteorder=byteorder, aligned=aligned)
- logging.debug("__new__ received %s" % type(data))
#
if isinstance(data, MultiTimeSeries):
cls._defaultfieldmask = data._series._fieldmask
@@ -142,7 +139,6 @@
"""
# mclass = self.__class__
#..........
- logging.debug("__wrap__ received %s" % type(obj))
if context is None:
# return mclass(obj, mask=self._mask, copy=False)
return MaskedArray(obj, mask=self._mask, copy=False,
@@ -157,7 +153,6 @@
def __array_finalize__(self,obj):
- logging.debug("__array_finalize__ received %s" % type(obj))
if isinstance(obj, MultiTimeSeries):
self.__dict__.update(_dates=obj._dates,
_series=obj._series,
@@ -167,8 +162,6 @@
_fill_value=obj._fill_value
)
else:
- logging.debug("__array_finalize__ dtype %s" % obj.dtype)
- logging.debug("__array_finalize__ mask %s" % self._defaultfieldmask)
self.__dict__.update(_data = obj.view(recarray),
_dates = self._defaultdates,
_series = MaskedRecords(obj, dtype=obj.dtype),
@@ -178,11 +171,9 @@
)
MultiTimeSeries._defaultfieldmask = nomask
MultiTimeSeries._defaulthardmask = False
-# logging.debug("__array_finalize__ exit ")
return
#......................................................
def __getattribute__(self, attr):
-# logging.debug('__getattribute__ %s' % attr)
try:
# Returns a generic attribute
return object.__getattribute__(self,attr)
@@ -190,7 +181,6 @@
# OK, so attr must be a field name
pass
# Get the list of fields ......
-# logging.debug('__getattribute__ %s listfield' % attr)
_names = self.dtype.names
_local = self.__dict__
_mask = _local['_fieldmask']
@@ -200,21 +190,18 @@
obj._mask = make_mask(_mask.__getattribute__(attr))
return obj
elif attr == '_mask':
-# logging.debug('__getattribute__ return mask')
if self.size > 1:
return _mask.view((bool_, len(self.dtype))).all(1)
return _mask.view((bool_, len(self.dtype)))
raise AttributeError,"No attribute '%s' !" % attr
def __setattr__(self, attr, val):
-# logging.debug('__setattribute__ %s' % attr)
newattr = attr not in self.__dict__
try:
# Is attr a generic attribute ?
ret = object.__setattr__(self, attr, val)
except:
# Not a generic attribute: exit if it's not a valid field
-# logging.debug('__setattribute__ %s' % attr)
fielddict = self.dtype.names or {}
if attr not in fielddict:
exctype, value = sys.exc_info()[:2]
@@ -242,16 +229,12 @@
elif attr == '_mask':
if self._hardmask:
val = make_mask(val)
- logging.debug("setattr: object has hardmask %s" % val)
- logging.debug("setattr: val is nomask: %s" % (val is nomask))
if val is not nomask:
# mval = getmaskarray(val)
for k in _names:
m = mask_or(val, base_fmask.__getattr__(k))
- logging.debug("setattr: %k to: %s" % (k,m))
base_fmask.__setattr__(k, m)
else:
- logging.debug("setattr: VAL IS NOMASK: %s" % (val is nomask))
return
else:
mval = getmaskarray(val)
@@ -262,14 +245,11 @@
def __getitem__(self, indx):
"""Returns all the fields sharing the same fieldname base.
The fieldname base is either `_data` or `_mask`."""
- logging.debug('__getitem__(%s)' % indx)
_localdict = self.__dict__
# We want a field ........
if indx in self.dtype.names:
- logging.debug('__getitem__ getfield %s' % indx)
obj = _localdict['_series'][indx].view(TimeSeries)
obj._mask = make_mask(_localdict['_fieldmask'][indx])
- logging.debug('__getitem__ field %s mask %s:' % (indx, obj._mask))
return obj
# We want some elements ..
indx = super(MultiTimeSeries, self)._TimeSeries__checkindex(indx)
@@ -280,7 +260,6 @@
def __getslice__(self, i, j):
"""Returns the slice described by [i,j]."""
- logging.debug("__Getslice__ [%i,%i]" % (i,j))
_localdict = self.__dict__
return MultiTimeSeries(_localdict['_data'][i:j],
mask=_localdict['_fieldmask'][i:j],
@@ -358,7 +337,6 @@
"""Returns a view of the mrecarray."""
try:
if issubclass(obj, ndarray):
-# logging.debug('direct view as %s' % obj)
return ndarray.view(self, obj)
except TypeError:
pass
@@ -426,7 +404,6 @@
# Define formats from scratch ...............
if formats is None and dtype is None:
formats = _getformats(arraylist)
-# logging.debug("fromarrays: formats",formats)
# Define the dtype ..........................
if dtype is not None:
descr = numeric.dtype(dtype)
@@ -545,7 +522,6 @@
line = f.readline()
firstline = line[:line.find(commentchar)].strip()
_varnames = firstline.split(delimitor)
-# logging.debug("_VARNAMES:%s-%s"% (_varnames,len(_varnames)))
if len(_varnames) > 1:
break
if varnames is None:
@@ -586,7 +562,6 @@
vartypes = _guessvartypes(_variables[0])
# Construct the descriptor ..................
mdescr = [(n,f) for (n,f) in zip(varnames, vartypes)]
-# logging.debug("fromtextfile: descr: %s" % mdescr)
# Get the data and the mask .................
# We just need a list of masked_arrays. It's easier to create it like that:
_mask = (_variables.T == missingchar)
Modified: trunk/Lib/sandbox/timeseries/tseries.py
===================================================================
--- trunk/Lib/sandbox/timeseries/tseries.py 2007-01-29 23:03:18 UTC (rev 2632)
+++ trunk/Lib/sandbox/timeseries/tseries.py 2007-01-30 04:08:29 UTC (rev 2633)
@@ -42,11 +42,11 @@
masked_array
import tcore as corelib
-#reload(corelib)
+reload(corelib)
from tcore import *
import tdates
-#reload(tdates)
+reload(tdates)
from tdates import DateError, InsufficientDateError
from tdates import Date, isDate, DateArray, isDateArray, \
date_array, date_array_fromlist, date_array_fromrange, thisday
@@ -64,12 +64,7 @@
]
#...............................................................................
-import logging
-logging.basicConfig(level=logging.DEBUG,
format='%(name)-15s %(levelname)s %(message)s',)
-talog = logging.getLogger('log.TimeArray')
-tslog = logging.getLogger('TimeSeries')
-btslog = logging.getLogger('BaseTimeSeries')
ufunc_domain = {}
ufunc_fills = {}
@@ -183,7 +178,7 @@
cls._defaultdates = newdates
# Check frequency......
if freq is not None:
- freq = corelib.fmtFreq(freq)
+ freq = corelib.check_freq(freq)[0]
if freq != newdates.freq:
_dates = newdates.tofreq(freq)
else:
@@ -265,32 +260,32 @@
super(self._series.__class__, self._series).__setattribute__(attr, value)
setattr(self._series, attr, value)
#............................................
- def __checkindex(self, index):
+ def __checkindex(self, indx):
"Checks the validity of an index."
- if isinstance(index, int):
- return index
- if isinstance(index, str):
- return self._dates.date_to_index(Date(self._dates.freq, string=index))
- elif isDate(index) or isDateArray(index):
- return self._dates.date_to_index(index)
- elif isinstance(index,slice):
- slice_start = self.__checkindex(index.start)
- slice_stop = self.__checkindex(index.stop)
- return slice(slice_start, slice_stop, index.step)
- elif isTimeSeries(index):
- index = index._series
- if getmask(index) is not nomask:
+ if isinstance(indx, int):
+ return indx
+ if isinstance(indx, str):
+ return self._dates.date_to_index(Date(self._dates.freq, string=indx))
+ elif isDate(indx) or isDateArray(indx):
+ return self._dates.date_to_index(indx)
+ elif isinstance(indx,slice):
+ slice_start = self.__checkindex(indx.start)
+ slice_stop = self.__checkindex(indx.stop)
+ return slice(slice_start, slice_stop, indx.step)
+ elif isTimeSeries(indx):
+ indx = indx._series
+ if getmask(indx) is not nomask:
msg = "Masked arrays must be filled before they can be used as indices!"
raise IndexError, msg
- return index
+ return indx
- def __getitem__(self, index):
+ def __getitem__(self, indx):
"""x.__getitem__(y) <==> x[y]
Returns the item described by i. Not a copy as in previous versions.
"""
- index = self.__checkindex(index)
- data = self._series[index]
- date = self._dates[index]
+ indx = self.__checkindex(indx)
+ data = self._series[indx]
+ date = self._dates[indx]
m = self._mask
scalardata = (len(numeric.shape(data))==0)
#
@@ -301,7 +296,7 @@
return TimeSeries(data, dates=date, mask=nomask, keep_mask=True,
copy=False)
#....
- mi = m[index]
+ mi = m[indx]
if mi.size == 1:
if mi:
return TimeSeries(data, dates=date, mask=True)
@@ -309,19 +304,19 @@
else:
return TimeSeries(data, dates=date, mask=mi)
#........................
- def __setitem__(self, index, value):
+ 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.'
- index = self.__checkindex(index)
+ indx = self.__checkindex(indx)
#....
if isinstance(value, TimeSeries):
- assert(_timeseriescompat(self[index], value))
- self._series[index] = value._series
+ assert(_timeseriescompat(self[indx], value))
+ self._series[indx] = value._series
else:
- self._series[index] = value
+ self._series[indx] = value
# Don't forget to update the mask !
self._mask = self._series._mask
@@ -338,7 +333,7 @@
i = self.__checkindex(i)
j = self.__checkindex(j)
#....
- data = self._series[i:j]
+# data = self._series[i:j]
if isinstance(value, TimeSeries):
assert(_timeseriescompat(self[i:j], value))
self._series[i:j] = value._series
@@ -379,10 +374,10 @@
if self.ndim <= 1:
return desc_short % {'data': str(self._series),
'time': timestr,
- 'freq': self.freq, }
+ 'freq': self.freqstr, }
return desc % {'data': str(self._series),
'time': timestr,
- 'freq': self.freq, }
+ 'freq': self.freqstr, }
#............................................
def _get_mask(self):
"""Returns the current mask."""
@@ -419,8 +414,12 @@
return self._dates
@property
def freq(self):
- """Returns the corresponding frequency."""
+ """Returns the corresponding frequency (as an integer)."""
return self._dates.freq
+ @property
+ def freqstr(self):
+ """Returns the corresponding frequency (as a string)."""
+ return self._dates.freqstr
@property
def day(self):
@@ -474,7 +473,6 @@
hours = hour
weeks = week
-
@property
def start_date(self):
"""Returns the first date of the series."""
@@ -482,7 +480,6 @@
return self._dates[0]
else:
return None
-
@property
def end_date(self):
"""Returns the last date of the series."""
@@ -490,7 +487,6 @@
return self._dates[-1]
else:
return None
-
def isvalid(self):
"""Returns whether the series has no duplicate/missing dates."""
@@ -517,8 +513,16 @@
if freq is None:
return self
return TimeSeries(self._series, dates=self._dates.asfreq(freq))
+
+ def convert(self, freq, func='auto', position='END'):
+ "Converts the dates to another frequency, and adapt the data."
+ return convert(self, freq, func=func, position=position)
+ #.....................................................
+ 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()
-
##### --------------------------------------------------------------------------
##--- ... Additional methods ...
##### --------------------------------------------------------------------------
@@ -681,7 +685,10 @@
TimeSeries.varu = _tsaxismethod('varu')
TimeSeries.std = _tsaxismethod('std')
TimeSeries.stdu = _tsaxismethod('stdu')
+TimeSeries.all = _tsaxismethod('all')
+TimeSeries.any = _tsaxismethod('any')
+
class _tsblockedmethods(object):
"""Defines a wrapper for array methods that should be temporarily disabled.
"""
@@ -930,16 +937,16 @@
start_date = data._dates[0]
elif isinstance(start_date, str):
start_date = Date(data.freq, string=start_date)
- elif not isDateType(start_date):
- raise DateError,"Starting date should be a valid date!"
+ elif not isinstance(start_date, Date):
+ raise DateError,"Starting date should be a valid Date object!"
start_date = max(start_date, data.dates[0])
# Check the ending date ................
if end_date is None:
end_date = data._dates[-1]
elif isinstance(end_date, str):
end_date = Date(data.freq, string=end_date)
- elif not isDateType(end_date):
- raise DateError,"Starting date should be a valid date!"
+ elif not isinstance(end_date, Date):
+ raise DateError,"Starting date should be a valid Date object!"
end_date = min(end_date, data.dates[-1])
# Constructs the selection mask .........
if inside:
@@ -984,64 +991,65 @@
if a.freq == 'U':
raise TimeSeriesError, \
"Cannot adjust a series with 'Undefined' frequency."
- if not a.dates.isvalid() and a.ndim > 0 and a.size > 1:
+ if not a.dates.isvalid():
raise TimeSeriesError, \
"Cannot adjust a series with missing or duplicated dates."
# Flatten the series if needed ..............
a = a.flatten()
shp_flat = a.shape
# Dates validity checks .,...................
- msg = "%s should be a valid Date instance! (got %s instead)"
-
- (dstart, dend) = a.start_date, a.end_date
- if dstart is not None:
-
- if start_date is None:
- start_date = dstart
- start_lag = 0
- else:
- if not isDateType(start_date):
- raise TypeError, msg % ('start_date', type(start_date))
+ msg = "%s should be a valid Date object! (got %s instead)"
+ if a.dates.size >= 1:
+ (dstart, dend) = a.dates[[0,-1]]
+ else:
+ (dstart, dend) = (None, None)
+ # Skip the empty series case
+ if dstart is None and (start_date is None or end_date is None):
+ raise TimeSeriesError, "Both start_date and end_date must be specified"+\
+ " to adjust endpoints of a zero length series!"
+ #....
+ if start_date is None:
+ start_date = dstart
+ start_lag = 0
+ else:
+ if not isinstance(start_date, Date):
+ raise TypeError, msg % ('start_date', type(start_date))
+ if dstart is not None:
start_lag = start_date - dstart
- #....
- if end_date is None:
- end_date = dend
- end_lag = 0
else:
- if not isDateType(end_date):
- raise TypeError, msg % ('end_date', type(end_date))
+ start_lag = start_date
+ #....
+ if end_date is None:
+ end_date = dend
+ end_lag = 0
+ else:
+ if not isinstance(end_date, Date):
+ raise TypeError, msg % ('end_date', type(end_date))
+ if dend is not None:
end_lag = end_date - dend
- # Check if the new range is included in the old one
- if start_lag >= 0:
- if end_lag == 0:
- return a[start_lag:]
- elif end_lag < 0:
- return a[start_lag:end_lag]
-
- else:
- if start_date is None or end_date is None:
- raise TimeSeriesError, \
- """start_date and end_date must be specified to adjust
-endpoints of a zero length series"""
-
+ else:
+ end_lag = end_date
+ # Check if the new range is included in the old one
+ if start_lag >= 0:
+ if end_lag == 0:
+ return a[start_lag:]
+ elif end_lag < 0:
+ return a[start_lag:end_lag]
# Create a new series .......................
newdates = date_array(start_date=start_date, end_date=end_date)
+
newshape = list(shp_flat)
newshape[0] = len(newdates)
newshape = tuple(newshape)
-
+
newdata = masked_array(numeric.empty(newshape, dtype=a.dtype), mask=True)
-
- # need to ensure that we preserve attributes of the series in the result
+ #backup the series attributes
options = dict(fill_value=a.fill_value, observed=a.observed)
-
newseries = TimeSeries(newdata, newdates, **options)
-
if dstart is not None:
start_date = max(start_date, dstart)
end_date = min(end_date, dend) + 1
newseries[start_date:end_date] = a[start_date:end_date]
-
return newseries
#....................................................................
def align_series(*series, **kwargs):
@@ -1056,7 +1064,7 @@
"""
if len(series) < 2:
return series
- unique_freqs = numpy.unique([x.freq for x in series])
+ unique_freqs = numpy.unique([x.freqstr for x in series])
try:
common_freq = unique_freqs.item()
except ValueError:
@@ -1065,15 +1073,19 @@
if common_freq == 'U':
raise TimeSeriesError, \
"Cannot adjust a series with 'Undefined' frequency."
- valid_states = [x.isvalid() or (x.size == 0 and x.ndim > 0) for x in series]
+ valid_states = [x.isvalid() for x in series]
if not numpy.all(valid_states):
raise TimeSeriesError, \
"Cannot adjust a series with missing or duplicated dates."
- start_date = kwargs.pop('start_date', min([x.start_date for x in series if x.start_date is not None]))
+ start_date = kwargs.pop('start_date',
+ min([x.start_date for x in series
+ if x.start_date is not None]))
if isinstance(start_date,str):
start_date = Date(common_freq, string=start_date)
- end_date = kwargs.pop('end_date', max([x.end_date for x in series if x.end_date is not None]))
+ end_date = kwargs.pop('end_date',
+ max([x.end_date for x in series
+ if x.end_date is not None]))
if isinstance(end_date,str):
end_date = Date(common_freq, string=end_date)
@@ -1137,7 +1149,9 @@
observed=series.observed,
start_date=start_date)
return newseries
-#....................................................................
+TimeSeries.convert = convert
+
+#...............................................................................
def tshift(series, nper):
"""Returns a series of the same size as `series`, with the same
start_date and end_date, but values shifted by `nper`. This is useful
@@ -1155,28 +1169,26 @@
dates = [2005 ... 2008],
freq = A)
"""
- newdata = masked_array(numeric.empty(series.shape, dtype=series.dtype), mask=True)
-
- # need to ensure that we preserve attributes of the series in the result
+ #Backup series attributes
options = dict(fill_value=series.fill_value, observed=series.observed)
- newseries = TimeSeries(newdata, series._dates, **options)
-
+ newdata = masked_array(numeric.empty(series.shape, dtype=series.dtype),
+ mask=True)
+ inidata = series._series.copy()
if nper < 0:
- nper = max(-series.shape[0],nper)
- newseries[-nper:] = series._series[:nper].copy()
- newseries[:-nper] = masked
+ nper = max(-len(series), nper)
+ newdata[-nper:] = inidata[:nper]
elif nper > 0:
- nper = min(series.shape[0],nper)
- newseries[-nper:] = masked
- newseries[:-nper] = series._series[nper:].copy()
+ nper = min(len(series), nper)
+ newdata[:-nper] = inidata[nper:]
else:
- newseries[:] = self._series[:].copy()
-
+ newdata = inidata
+ newseries = TimeSeries(newdata, series._dates, **options)
return newseries
+TimeSeries.tshift = tshift
#....................................................................
-TimeSeries.convert = convert
-TimeSeries.tshift = tshift
+
+
#....................................................................
def fill_missing_dates(data, dates=None, freq=None,fill_value=None):
"""Finds and fills the missing dates in a time series.
@@ -1193,10 +1205,10 @@
`fill_value` : float *[None]*
Default value for missing data. If None, the data are just masked.
"""
- freq = corelib.fmtFreq(freq)
- if freq == 'U':
+ (freq, freqstr) = corelib.check_freq(freq)
+ if freqstr == 'U':
raise ValueError,\
- "Unable to define a proper date resolution (found %s)." % freq
+ "Unable to define a proper date resolution (found %s)." % freqstr
if dates is None:
if not isTimeSeries(data):
raise InsufficientDateError
@@ -1272,7 +1284,6 @@
################################################################################
if __name__ == '__main__':
- logging.basicConfig(level=logging.DEBUG)
from maskedarray.testutils import assert_equal
# if 0:
# dlist = ['2007-01-%02i' % i for i in range(1,16)]
@@ -1331,7 +1342,14 @@
dates = date_array_fromlist(dlist)
data = masked_array(numeric.arange(15), mask=[1,0,0,0,0]*3, dtype=float_)
self_d = (time_series(range(15), dlist), data, dates)
- (series, data, dates) = self_d
+ (ser, data, dates) = self_d
+
+ if 1:
+ hodie = tdates.today('M')
+ ser_0 = time_series([], [], freq='M')
+ ser_2 = time_series([1,2], start_date=hodie)
+ ser_1 = time_series([1], hodie, freq='M')
+
# # Testing a basic condition on data
# cond = (series<8).filled(False)
# dseries = series[cond]
More information about the Scipy-svn
mailing list