Skip to content

Commit c834758

Browse files
stephenwlinwesm
authored andcommitted
ENH: time slicing on datetime indicies
1 parent 68c0f34 commit c834758

File tree

4 files changed

+104
-26
lines changed

4 files changed

+104
-26
lines changed

pandas/core/index.py

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,30 @@ def _wrap_joined_index(self, joined, other):
11171117
name = self.name if self.name == other.name else None
11181118
return Index(joined, name=name)
11191119

1120+
def slice_indexer(self, start=None, end=None, step=None):
1121+
"""
1122+
For an ordered Index, compute the slice indexer for input labels and
1123+
step
1124+
1125+
Parameters
1126+
----------
1127+
start : label, default None
1128+
If None, defaults to the beginning
1129+
end : label, default None
1130+
If None, defaults to the end
1131+
step : int, default None
1132+
1133+
Returns
1134+
-------
1135+
indexer : ndarray or slice
1136+
1137+
Notes
1138+
-----
1139+
This function assumes that the data is sorted, so use at your own peril
1140+
"""
1141+
start_slice, end_slice = self.slice_locs(start, end)
1142+
return slice(start_slice, end_slice, step)
1143+
11201144
def slice_locs(self, start=None, end=None):
11211145
"""
11221146
For an ordered Index, compute the slice locations for input labels
@@ -1125,27 +1149,27 @@ def slice_locs(self, start=None, end=None):
11251149
----------
11261150
start : label, default None
11271151
If None, defaults to the beginning
1128-
end : label
1152+
end : label, default None
11291153
If None, defaults to the end
11301154
11311155
Returns
11321156
-------
1133-
(begin, end) : (int, int)
1157+
(start, end) : (int, int)
11341158
11351159
Notes
11361160
-----
11371161
This function assumes that the data is sorted, so use at your own peril
11381162
"""
11391163
if start is None:
1140-
beg_slice = 0
1164+
start_slice = 0
11411165
else:
11421166
try:
1143-
beg_slice = self.get_loc(start)
1144-
if isinstance(beg_slice, slice):
1145-
beg_slice = beg_slice.start
1167+
start_slice = self.get_loc(start)
1168+
if isinstance(start_slice, slice):
1169+
start_slice = start_slice.start
11461170
except KeyError:
11471171
if self.is_monotonic:
1148-
beg_slice = self.searchsorted(start, side='left')
1172+
start_slice = self.searchsorted(start, side='left')
11491173
else:
11501174
raise
11511175

@@ -1164,7 +1188,7 @@ def slice_locs(self, start=None, end=None):
11641188
else:
11651189
raise
11661190

1167-
return beg_slice, end_slice
1191+
return start_slice, end_slice
11681192

11691193
def delete(self, loc):
11701194
"""
@@ -2106,7 +2130,7 @@ def slice_locs(self, start=None, end=None, strict=False):
21062130
21072131
Returns
21082132
-------
2109-
(begin, end) : (int, int)
2133+
(start, end) : (int, int)
21102134
21112135
Notes
21122136
-----

pandas/core/indexing.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -462,20 +462,19 @@ def _convert_to_indexer(self, obj, axis=0):
462462
raise
463463

464464
if null_slice or position_slice:
465-
slicer = obj
465+
indexer = obj
466466
else:
467467
try:
468-
i, j = labels.slice_locs(start, stop)
469-
slicer = slice(i, j, obj.step)
468+
indexer = labels.slice_indexer(start, stop, obj.step)
470469
except Exception:
471470
if _is_index_slice(obj):
472471
if labels.inferred_type == 'integer':
473472
raise
474-
slicer = obj
473+
indexer = obj
475474
else:
476475
raise
477476

478-
return slicer
477+
return indexer
479478

480479
elif _is_list_like(obj):
481480
if com._is_bool_indexer(obj):
@@ -535,8 +534,10 @@ def _tuplify(self, loc):
535534
def _get_slice_axis(self, slice_obj, axis=0):
536535
obj = self.obj
537536

538-
axis_name = obj._get_axis_name(axis)
539-
labels = getattr(obj, axis_name)
537+
if not _need_slice(slice_obj):
538+
return obj
539+
540+
labels = obj._get_axis(axis)
540541

541542
int_slice = _is_index_slice(slice_obj)
542543

@@ -569,23 +570,22 @@ def _get_slice_axis(self, slice_obj, axis=0):
569570
raise
570571

571572
if null_slice or position_slice:
572-
slicer = slice_obj
573+
indexer = slice_obj
573574
else:
574575
try:
575-
i, j = labels.slice_locs(start, stop)
576-
slicer = slice(i, j, slice_obj.step)
576+
indexer = labels.slice_indexer(start, stop, slice_obj.step)
577577
except Exception:
578578
if _is_index_slice(slice_obj):
579579
if labels.inferred_type == 'integer':
580580
raise
581-
slicer = slice_obj
581+
indexer = slice_obj
582582
else:
583583
raise
584584

585-
if not _need_slice(slice_obj):
586-
return obj
587-
588-
return self._slice(slicer, axis=axis)
585+
if isinstance(indexer, slice):
586+
return self._slice(indexer, axis=axis)
587+
else:
588+
return self.obj.take(indexer, axis=axis)
589589

590590
# 32-bit floating point machine epsilon
591591
_eps = np.finfo('f4').eps

pandas/tests/test_frame.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# pylint: disable-msg=W0612,E1101
22
from copy import deepcopy
3-
from datetime import datetime, timedelta
3+
from datetime import datetime, timedelta, time
44
from StringIO import StringIO
55
import cPickle as pickle
66
import operator
@@ -4552,7 +4552,6 @@ def test_asfreq(self):
45524552
self.assert_(result is not zero_length)
45534553

45544554
def test_asfreq_datetimeindex(self):
4555-
from pandas import DatetimeIndex
45564555
df = DataFrame({'A': [1, 2, 3]},
45574556
index=[datetime(2011, 11, 01), datetime(2011, 11, 2),
45584557
datetime(2011, 11, 3)])
@@ -4562,6 +4561,44 @@ def test_asfreq_datetimeindex(self):
45624561
ts = df['A'].asfreq('B')
45634562
self.assert_(isinstance(ts.index, DatetimeIndex))
45644563

4564+
def test_attime_betweentime_datetimeindex(self):
4565+
index = pan.date_range("2012-01-01", "2012-01-05", freq='30min')
4566+
df = DataFrame(randn(len(index), 5), index=index)
4567+
4568+
result = df.at_time(time(12, 0, 0))
4569+
expected = df.ix[time(12, 0, 0)]
4570+
assert_frame_equal(result, expected)
4571+
self.assert_(len(result) == 4)
4572+
4573+
result = df.between_time(time(13, 0, 0), time(14, 0, 0))
4574+
expected = df.ix[time(13, 0, 0):time(14, 0, 0)]
4575+
assert_frame_equal(result, expected)
4576+
self.assert_(len(result) == 12)
4577+
4578+
result = df.copy()
4579+
result.ix[time(12, 0, 0)] = 0
4580+
result = result.ix[time(12, 0, 0)]
4581+
expected = df.ix[time(12, 0, 0)].copy()
4582+
expected.ix[:] = 0
4583+
assert_frame_equal(result, expected)
4584+
4585+
result = df.copy()
4586+
result.ix[time(12, 0, 0)] = 0
4587+
result.ix[time(12, 0, 0)] = df # also checks reindexing
4588+
assert_frame_equal(result, df)
4589+
4590+
result = df.copy()
4591+
result.ix[time(13, 0, 0):time(14, 0, 0)] = 0
4592+
result = result.ix[time(13, 0, 0):time(14, 0, 0)]
4593+
expected = df.ix[time(13, 0, 0):time(14, 0, 0)].copy()
4594+
expected.ix[:] = 0
4595+
assert_frame_equal(result, expected)
4596+
4597+
result = df.copy()
4598+
result.ix[time(13, 0, 0):time(14, 0, 0)] = 0
4599+
result.ix[time(13, 0, 0):time(14, 0, 0)] = df # also checks reindexing
4600+
assert_frame_equal(result, df)
4601+
45654602
def test_as_matrix(self):
45664603
frame = self.frame
45674604
mat = frame.as_matrix()

pandas/tseries/index.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,20 @@ def _get_string_slice(self, key):
11521152
loc = self._partial_date_slice(reso, parsed)
11531153
return loc
11541154

1155+
def slice_indexer(self, start=None, end=None, step=None):
1156+
"""
1157+
Index.slice_indexer, customized to handle time slicing
1158+
"""
1159+
if isinstance(start, time) and isinstance(end, time):
1160+
if step is not None and step != 1:
1161+
raise ValueError('Must have step size of 1 with time slices')
1162+
return self.indexer_between_time(start, end)
1163+
1164+
if isinstance(start, time) or isinstance(end, time):
1165+
raise KeyError('Cannot mix time and non-time slice keys')
1166+
1167+
return Index.slice_indexer(self, start, end, step)
1168+
11551169
def slice_locs(self, start=None, end=None):
11561170
"""
11571171
Index.slice_locs, customized to handle partial ISO-8601 string slicing
@@ -1172,6 +1186,9 @@ def slice_locs(self, start=None, end=None):
11721186
except KeyError:
11731187
pass
11741188

1189+
if isinstance(start, time) or isinstance(end, time):
1190+
raise KeyError('Cannot use slice_locs with time slice keys')
1191+
11751192
return Index.slice_locs(self, start, end)
11761193

11771194
def __getitem__(self, key):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy