Skip to content

Commit 3418cc8

Browse files
committed
ENH: implement asfreq with PeriodIndex on Series/DataFrame, close #1129
1 parent 828a218 commit 3418cc8

File tree

6 files changed

+73
-68
lines changed

6 files changed

+73
-68
lines changed

pandas/core/frame.py

-23
Original file line numberDiff line numberDiff line change
@@ -2929,29 +2929,6 @@ def unstack(self, level=-1):
29292929
#----------------------------------------------------------------------
29302930
# Time series-related
29312931

2932-
def asfreq(self, freq, method=None):
2933-
"""
2934-
Convert all TimeSeries inside to specified frequency using DateOffset
2935-
objects. Optionally provide fill method to pad/backfill missing values.
2936-
2937-
Parameters
2938-
----------
2939-
freq : DateOffset object, or string
2940-
method : {'backfill', 'bfill', 'pad', 'ffill', None}
2941-
Method to use for filling holes in reindexed Series
2942-
pad / ffill: propagate last valid observation forward to next valid
2943-
backfill / bfill: use NEXT valid observation to fill methdo
2944-
2945-
Returns
2946-
-------
2947-
converted : DataFrame
2948-
"""
2949-
from pandas.tseries.index import date_range
2950-
if len(self.index) == 0:
2951-
return self.copy()
2952-
dti = date_range(self.index[0], self.index[-1], freq=freq)
2953-
return self.reindex(dti, method=method)
2954-
29552932
def diff(self, periods=1):
29562933
"""
29572934
1st discrete difference of object

pandas/core/generic.py

+22
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,28 @@ def groupby(self, by=None, axis=0, level=None, as_index=True, sort=True,
135135
return groupby(self, by, axis=axis, level=level, as_index=as_index,
136136
sort=sort, group_keys=group_keys)
137137

138+
def asfreq(self, freq, method=None, how=None):
139+
"""
140+
Convert all TimeSeries inside to specified frequency using DateOffset
141+
objects. Optionally provide fill method to pad/backfill missing values.
142+
143+
Parameters
144+
----------
145+
freq : DateOffset object, or string
146+
method : {'backfill', 'bfill', 'pad', 'ffill', None}
147+
Method to use for filling holes in reindexed Series
148+
pad / ffill: propagate last valid observation forward to next valid
149+
backfill / bfill: use NEXT valid observation to fill methdo
150+
how : {'start', 'end'}, default end
151+
For PeriodIndex only, see PeriodIndex.asfreq
152+
153+
Returns
154+
-------
155+
converted : type of caller
156+
"""
157+
from pandas.tseries.resample import asfreq
158+
return asfreq(self, freq, method=method, how=how)
159+
138160
def resample(self, rule, how='mean', axis=0, as_index=True,
139161
fill_method=None, closed='right', label='right', kind=None):
140162
"""

pandas/core/series.py

-23
Original file line numberDiff line numberDiff line change
@@ -2295,29 +2295,6 @@ def asof(self, date):
22952295
else:
22962296
return v
22972297

2298-
def asfreq(self, freq, method=None):
2299-
"""
2300-
Convert all TimeSeries inside to specified frequency using DateOffset
2301-
objects. Optionally provide fill method to pad/backfill missing values.
2302-
2303-
Parameters
2304-
----------
2305-
freq : DateOffset object, or string
2306-
method : {'backfill', 'bfill', 'pad', 'ffill', None}
2307-
Method to use for filling holes in reindexed Series
2308-
pad / ffill: propagate last valid observation forward to next valid
2309-
backfill / bfill: use NEXT valid observation to fill methdo
2310-
2311-
Returns
2312-
-------
2313-
converted : DataFrame
2314-
"""
2315-
from pandas.tseries.index import date_range
2316-
if len(self.index) == 0:
2317-
return self.copy()
2318-
dti = date_range(self.index[0], self.index[-1], freq=freq)
2319-
return self.reindex(dti, method=method)
2320-
23212298
def interpolate(self, method='linear'):
23222299
"""
23232300
Interpolate missing values (after the first valid value)

pandas/tseries/period.py

+4
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,10 @@ def __iter__(self):
551551
def is_all_dates(self):
552552
return True
553553

554+
@property
555+
def freqstr(self):
556+
return self.freq
557+
554558
def asfreq(self, freq=None, how='E'):
555559
how = _validate_end_alias(how)
556560

pandas/tseries/resample.py

+22-21
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from pandas.core.groupby import BinGrouper
44
from pandas.tseries.frequencies import to_offset
5-
from pandas.tseries.index import DatetimeIndex
5+
from pandas.tseries.index import DatetimeIndex, date_range
66
from pandas.tseries.offsets import DateOffset
77
from pandas.tseries.period import PeriodIndex
88
from pandas.util.decorators import cache_readonly
@@ -147,26 +147,6 @@ def result_index(self):
147147

148148

149149
def _get_range_edges(axis, begin, end, offset, closed='left'):
150-
# from pandas.tseries.tools import _delta_to_microseconds
151-
152-
# if isinstance(offset, Tick):
153-
# if begin is None:
154-
# if closed == 'left':
155-
# first = Timestamp(offset.rollback(axis[0]))
156-
# else:
157-
# first = Timestamp(axis[0] - offset)
158-
# else:
159-
# first = Timestamp(offset.rollback(begin))
160-
161-
# if end is None:
162-
# if closed == 'left':
163-
# last = Timestamp(axis[-1] + offset)
164-
# else:
165-
# last = Timestamp(offset.rollforward(axis[-1]))
166-
# else:
167-
# last = Timestamp(offset.rollforward(end))
168-
# else:
169-
170150
if begin is None:
171151
if closed == 'left':
172152
first = Timestamp(offset.rollback(axis[0]))
@@ -182,3 +162,24 @@ def _get_range_edges(axis, begin, end, offset, closed='left'):
182162
last = Timestamp(offset.rollforward(end))
183163

184164
return first, last
165+
166+
def asfreq(obj, freq, method=None, how=None):
167+
"""
168+
Utility frequency conversion method for Series/DataFrame
169+
"""
170+
if isinstance(obj.index, PeriodIndex):
171+
if method is not None:
172+
raise NotImplementedError
173+
174+
if how is None:
175+
how = 'E'
176+
177+
new_index = obj.index.asfreq(freq, how=how)
178+
new_obj = obj.copy()
179+
new_obj.index = new_index
180+
return new_obj
181+
else:
182+
if len(obj.index) == 0:
183+
return obj.copy()
184+
dti = date_range(obj.index[0], obj.index[-1], freq=freq)
185+
return obj.reindex(dti, method=method)

pandas/tseries/tests/test_period.py

+25-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import pandas.core.datetools as datetools
1919
import numpy as np
2020

21-
from pandas import Series, TimeSeries
21+
from pandas import Series, TimeSeries, DataFrame
2222
from pandas.util.testing import assert_series_equal
2323

2424
class TestPeriodProperties(TestCase):
@@ -862,6 +862,9 @@ class TestPeriodIndex(TestCase):
862862
def __init__(self, *args, **kwds):
863863
TestCase.__init__(self, *args, **kwds)
864864

865+
def setUp(self):
866+
pass
867+
865868
def test_make_time_series(self):
866869
index = PeriodIndex(freq='A', start='1/1/2001', end='12/1/2009')
867870
series = Series(1, index=index)
@@ -1056,6 +1059,27 @@ def test_asfreq(self):
10561059

10571060
#self.assertEquals(ii7.asfreq('A', 'E'), i_end)
10581061

1062+
def test_ts_repr(self):
1063+
index = PeriodIndex(freq='A', start='1/1/2001', end='12/31/2010')
1064+
ts = Series(np.random.randn(len(index)), index=index)
1065+
repr(ts)
1066+
1067+
def test_asfreq_ts(self):
1068+
index = PeriodIndex(freq='A', start='1/1/2001', end='12/31/2010')
1069+
ts = Series(np.random.randn(len(index)), index=index)
1070+
df = DataFrame(np.random.randn(len(index), 3), index=index)
1071+
1072+
result = ts.asfreq('D', how='end')
1073+
df_result = df.asfreq('D', how='end')
1074+
exp_index = index.asfreq('D', how='end')
1075+
self.assert_(len(result) == len(ts))
1076+
self.assert_(result.index.equals(exp_index))
1077+
self.assert_(df_result.index.equals(exp_index))
1078+
1079+
result = ts.asfreq('D', how='start')
1080+
self.assert_(len(result) == len(ts))
1081+
self.assert_(result.index.equals(index.asfreq('D', how='start')))
1082+
10591083
def test_badinput(self):
10601084
self.assertRaises(datetools.DateParseError, Period, '1/1/-2000', 'A')
10611085
self.assertRaises(ValueError, Period, -2000, 'A')

0 commit comments

Comments
 (0)