Skip to content

Commit 2420972

Browse files
committed
ENH: between_time, at_time accept axis parameter
1 parent 04caa56 commit 2420972

File tree

3 files changed

+78
-6
lines changed

3 files changed

+78
-6
lines changed

pandas/core/generic.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6760,7 +6760,7 @@ def asfreq(self, freq, method=None, how=None, normalize=False,
67606760
return asfreq(self, freq, method=method, how=how, normalize=normalize,
67616761
fill_value=fill_value)
67626762

6763-
def at_time(self, time, asof=False):
6763+
def at_time(self, time, asof=False, axis=None):
67646764
"""
67656765
Select values at particular time of day (e.g. 9:30AM).
67666766
@@ -6772,6 +6772,7 @@ def at_time(self, time, asof=False):
67726772
Parameters
67736773
----------
67746774
time : datetime.time or string
6775+
axis : int or string axis name, optional
67756776
67766777
Returns
67776778
-------
@@ -6801,14 +6802,19 @@ def at_time(self, time, asof=False):
68016802
DatetimeIndex.indexer_at_time : Get just the index locations for
68026803
values at particular time of the day
68036804
"""
6805+
if axis is None:
6806+
axis = self._stat_axis_number
6807+
axis = self._get_axis_number(axis)
6808+
68046809
try:
6805-
indexer = self.index.indexer_at_time(time, asof=asof)
6806-
return self._take(indexer)
6810+
index = self._get_axis(axis)
6811+
indexer = index.indexer_at_time(time, asof=asof)
6812+
return self._take(indexer, axis=axis)
68076813
except AttributeError:
68086814
raise TypeError('Index must be DatetimeIndex')
68096815

68106816
def between_time(self, start_time, end_time, include_start=True,
6811-
include_end=True):
6817+
include_end=True, axis=None):
68126818
"""
68136819
Select values between particular times of the day (e.g., 9:00-9:30 AM).
68146820
@@ -6826,6 +6832,7 @@ def between_time(self, start_time, end_time, include_start=True,
68266832
end_time : datetime.time or string
68276833
include_start : boolean, default True
68286834
include_end : boolean, default True
6835+
axis : int or string axis name, optional
68296836
68306837
Returns
68316838
-------
@@ -6863,11 +6870,16 @@ def between_time(self, start_time, end_time, include_start=True,
68636870
DatetimeIndex.indexer_between_time : Get just the index locations for
68646871
values between particular times of the day
68656872
"""
6873+
if axis is None:
6874+
axis = self._stat_axis_number
6875+
axis = self._get_axis_number(axis)
6876+
68666877
try:
6867-
indexer = self.index.indexer_between_time(
6878+
index = self._get_axis(axis)
6879+
indexer = index.indexer_between_time(
68686880
start_time, end_time, include_start=include_start,
68696881
include_end=include_end)
6870-
return self._take(indexer)
6882+
return self._take(indexer, axis=axis)
68716883
except AttributeError:
68726884
raise TypeError('Index must be DatetimeIndex')
68736885

pandas/tests/frame/test_timeseries.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,22 @@ def test_at_time_raises(self):
640640
with pytest.raises(TypeError): # index is not a DatetimeIndex
641641
df.at_time('00:00')
642642

643+
def test_at_time_axis(self):
644+
rng = date_range('1/1/2000', '1/5/2000', freq='5min')
645+
ts = DataFrame(np.random.randn(len(rng), len(rng)))
646+
647+
indices = rng[(rng.hour == 9) & (rng.minute == 30) & (rng.second == 0)]
648+
649+
ts.index = rng
650+
expected = ts.loc[indices]
651+
result = ts.at_time('9:30', axis=0)
652+
assert_frame_equal(result, expected)
653+
654+
ts.columns = rng
655+
expected = ts.loc[:,indices]
656+
result = ts.at_time('9:30', axis=1)
657+
assert_frame_equal(result, expected)
658+
643659
def test_between_time(self):
644660
rng = date_range('1/1/2000', '1/5/2000', freq='5min')
645661
ts = DataFrame(np.random.randn(len(rng), 2), index=rng)
@@ -706,6 +722,40 @@ def test_between_time_raises(self):
706722
with pytest.raises(TypeError): # index is not a DatetimeIndex
707723
df.between_time(start_time='00:00', end_time='12:00')
708724

725+
def test_between_time_axis(self):
726+
rng = date_range('1/1/2000', periods=100, freq='10min')
727+
blank = np.arange(0,len(rng))
728+
stime, etime = ('08:00:00', '09:00:00')
729+
dimn = (len(rng), len(rng))
730+
exp_len = 7
731+
732+
for time_index, time_col in product([True, False], [True, False]):
733+
if time_index:
734+
index = rng
735+
else:
736+
index = blank
737+
if time_col:
738+
col = rng
739+
else:
740+
col = blank
741+
742+
ts = DataFrame(np.random.randn(*dimn), index=index, columns=col)
743+
744+
if time_index:
745+
assert len(ts.between_time(stime, etime)) == exp_len
746+
assert len(ts.between_time(stime, etime, axis=0)) == exp_len
747+
else:
748+
pytest.raises(TypeError, ts.between_time, stime, etime)
749+
pytest.raises(TypeError, ts.between_time, stime, etime,
750+
axis=0)
751+
752+
if time_col:
753+
selected = ts.between_time(stime, etime, axis=1).columns
754+
assert len(selected) == exp_len
755+
else:
756+
pytest.raises(TypeError, ts.between_time, stime, etime,
757+
axis=1)
758+
709759
def test_operation_on_NaT(self):
710760
# Both NaT and Timestamp are in DataFrame.
711761
df = pd.DataFrame({'foo': [pd.NaT, pd.NaT,

pandas/tests/series/test_timeseries.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,16 @@ def test_between_time_formats(self):
817817
for time_string in strings:
818818
assert len(ts.between_time(*time_string)) == expected_length
819819

820+
def test_between_time_axis(self):
821+
rng = date_range('1/1/2000', periods=100, freq='10min')
822+
ts = Series(np.random.randn(len(rng)), index=rng)
823+
stime, etime = ('08:00:00', '09:00:00')
824+
expected_length = 7
825+
826+
assert len(ts.between_time(stime, etime)) == expected_length
827+
assert len(ts.between_time(stime, etime, axis=0)) == expected_length
828+
pytest.raises(ValueError, ts.between_time, stime, etime, axis=1)
829+
820830
def test_to_period(self):
821831
from pandas.core.indexes.period import period_range
822832

0 commit comments

Comments
 (0)