Skip to content

Commit 357286e

Browse files
committed
ENH: between_time, at_time accept axis parameter
1 parent 35dd15b commit 357286e

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
@@ -7012,7 +7012,7 @@ def asfreq(self, freq, method=None, how=None, normalize=False,
70127012
return asfreq(self, freq, method=method, how=how, normalize=normalize,
70137013
fill_value=fill_value)
70147014

7015-
def at_time(self, time, asof=False):
7015+
def at_time(self, time, asof=False, axis=None):
70167016
"""
70177017
Select values at particular time of day (e.g. 9:30AM).
70187018
@@ -7024,6 +7024,7 @@ def at_time(self, time, asof=False):
70247024
Parameters
70257025
----------
70267026
time : datetime.time or string
7027+
axis : int or string axis name, optional
70277028
70287029
Returns
70297030
-------
@@ -7053,14 +7054,19 @@ def at_time(self, time, asof=False):
70537054
DatetimeIndex.indexer_at_time : Get just the index locations for
70547055
values at particular time of the day
70557056
"""
7057+
if axis is None:
7058+
axis = self._stat_axis_number
7059+
axis = self._get_axis_number(axis)
7060+
70567061
try:
7057-
indexer = self.index.indexer_at_time(time, asof=asof)
7058-
return self._take(indexer)
7062+
index = self._get_axis(axis)
7063+
indexer = index.indexer_at_time(time, asof=asof)
7064+
return self._take(indexer, axis=axis)
70597065
except AttributeError:
70607066
raise TypeError('Index must be DatetimeIndex')
70617067

70627068
def between_time(self, start_time, end_time, include_start=True,
7063-
include_end=True):
7069+
include_end=True, axis=None):
70647070
"""
70657071
Select values between particular times of the day (e.g., 9:00-9:30 AM).
70667072
@@ -7078,6 +7084,7 @@ def between_time(self, start_time, end_time, include_start=True,
70787084
end_time : datetime.time or string
70797085
include_start : boolean, default True
70807086
include_end : boolean, default True
7087+
axis : int or string axis name, optional
70817088
70827089
Returns
70837090
-------
@@ -7115,11 +7122,16 @@ def between_time(self, start_time, end_time, include_start=True,
71157122
DatetimeIndex.indexer_between_time : Get just the index locations for
71167123
values between particular times of the day
71177124
"""
7125+
if axis is None:
7126+
axis = self._stat_axis_number
7127+
axis = self._get_axis_number(axis)
7128+
71187129
try:
7119-
indexer = self.index.indexer_between_time(
7130+
index = self._get_axis(axis)
7131+
indexer = index.indexer_between_time(
71207132
start_time, end_time, include_start=include_start,
71217133
include_end=include_end)
7122-
return self._take(indexer)
7134+
return self._take(indexer, axis=axis)
71237135
except AttributeError:
71247136
raise TypeError('Index must be DatetimeIndex')
71257137

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
@@ -825,6 +825,16 @@ def test_between_time_formats(self):
825825
for time_string in strings:
826826
assert len(ts.between_time(*time_string)) == expected_length
827827

828+
def test_between_time_axis(self):
829+
rng = date_range('1/1/2000', periods=100, freq='10min')
830+
ts = Series(np.random.randn(len(rng)), index=rng)
831+
stime, etime = ('08:00:00', '09:00:00')
832+
expected_length = 7
833+
834+
assert len(ts.between_time(stime, etime)) == expected_length
835+
assert len(ts.between_time(stime, etime, axis=0)) == expected_length
836+
pytest.raises(ValueError, ts.between_time, stime, etime, axis=1)
837+
828838
def test_to_period(self):
829839
from pandas.core.indexes.period import period_range
830840

0 commit comments

Comments
 (0)