Skip to content

BUG: TimedeltaIndex slicing may reset freq #10292

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 7, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v0.16.2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Bug Fixes

- Bug in ``Series.align`` resets ``name`` when ``fill_value`` is specified (:issue:`10067`)
- Bug in ``SparseSeries.abs`` resets ``name`` (:issue:`10241`)

- Bug in ``TimedeltaIndex`` slicing may reset freq (:issue:`10292`)

- Bug in GroupBy.get_group raises ValueError when group key contains NaT (:issue:`6992`)
- Bug in ``SparseSeries`` constructor ignores input data name (:issue:`10258`)
Expand Down
29 changes: 29 additions & 0 deletions pandas/tseries/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,35 @@ def __contains__(self, key):
except (KeyError, TypeError, ValueError):
return False

def __getitem__(self, key):
getitem = self._data.__getitem__
if np.isscalar(key):
val = getitem(key)
return self._box_func(val)
else:
if com.is_bool_indexer(key):
key = np.asarray(key)
if key.all():
key = slice(0, None, None)
else:
key = lib.maybe_booleans_to_slice(key.view(np.uint8))

attribs = self._get_attributes_dict()

freq = None
if isinstance(key, slice):
if self.freq is not None and key.step is not None:
freq = key.step * self.freq
else:
freq = self.freq
attribs['freq'] = freq

result = getitem(key)
if result.ndim > 1:
return result

return self._simple_new(result, **attribs)

@property
def freqstr(self):
""" return the frequency object as a string if its set, otherwise None """
Expand Down
26 changes: 0 additions & 26 deletions pandas/tseries/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -1349,32 +1349,6 @@ def slice_indexer(self, start=None, end=None, step=None, kind=None):
else:
raise

def __getitem__(self, key):
getitem = self._data.__getitem__
if np.isscalar(key):
val = getitem(key)
return Timestamp(val, offset=self.offset, tz=self.tz)
else:
if com.is_bool_indexer(key):
key = np.asarray(key)
if key.all():
key = slice(0,None,None)
else:
key = lib.maybe_booleans_to_slice(key.view(np.uint8))

new_offset = None
if isinstance(key, slice):
if self.offset is not None and key.step is not None:
new_offset = key.step * self.offset
else:
new_offset = self.offset

result = getitem(key)
if result.ndim > 1:
return result

return self._simple_new(result, self.name, new_offset, self.tz)

# alias to offset
def _get_freq(self):
return self.offset
Expand Down
21 changes: 1 addition & 20 deletions pandas/tseries/tdi.py
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ def _generate(cls, start, end, periods, name, offset, closed=None):

@property
def _box_func(self):
return lambda x: Timedelta(x,unit='ns')
return lambda x: Timedelta(x, unit='ns')

@classmethod
def _simple_new(cls, values, name=None, freq=None, **kwargs):
Expand Down Expand Up @@ -747,25 +747,6 @@ def _partial_td_slice(self, key, freq, use_lhs=True, use_rhs=True):
# try to find a the dates
return (lhs_mask & rhs_mask).nonzero()[0]

def __getitem__(self, key):
getitem = self._data.__getitem__
if np.isscalar(key):
val = getitem(key)
return Timedelta(val)
else:
if com.is_bool_indexer(key):
key = np.asarray(key)
if key.all():
key = slice(0,None,None)
else:
key = lib.maybe_booleans_to_slice(key.view(np.uint8))

result = getitem(key)
if result.ndim > 1:
return result

return self._simple_new(result, self.name)

def searchsorted(self, key, side='left'):
if isinstance(key, (np.ndarray, Index)):
key = np.array(key, dtype=_TD_DTYPE, copy=False)
Expand Down
59 changes: 59 additions & 0 deletions pandas/tseries/tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,38 @@ def test_nonunique_contains(self):
['2015', '2015', '2016'], ['2015', '2015', '2014'])):
tm.assertIn(idx[0], idx)

def test_getitem(self):
idx1 = pd.date_range('2011-01-01', '2011-01-31', freq='D', name='idx')
idx2 = pd.date_range('2011-01-01', '2011-01-31', freq='D', tz='Asia/Tokyo', name='idx')

for idx in [idx1, idx2]:
result = idx[0]
self.assertEqual(result, pd.Timestamp('2011-01-01', tz=idx.tz))

result = idx[0:5]
expected = pd.date_range('2011-01-01', '2011-01-05', freq='D',
tz=idx.tz, name='idx')
self.assert_index_equal(result, expected)
self.assertEqual(result.freq, expected.freq)

result = idx[0:10:2]
expected = pd.date_range('2011-01-01', '2011-01-09', freq='2D',
tz=idx.tz, name='idx')
self.assert_index_equal(result, expected)
self.assertEqual(result.freq, expected.freq)

result = idx[-20:-5:3]
expected = pd.date_range('2011-01-12', '2011-01-25', freq='3D',
tz=idx.tz, name='idx')
self.assert_index_equal(result, expected)
self.assertEqual(result.freq, expected.freq)

result = idx[4::-1]
expected = DatetimeIndex(['2011-01-05', '2011-01-04', '2011-01-03',
'2011-01-02', '2011-01-01'],
freq='-1D', tz=idx.tz, name='idx')
self.assert_index_equal(result, expected)
self.assertEqual(result.freq, expected.freq)

class TestTimedeltaIndexOps(Ops):

Expand Down Expand Up @@ -742,6 +774,33 @@ def test_unknown_attribute(self):
self.assertNotIn('foo',ts.__dict__.keys())
self.assertRaises(AttributeError,lambda : ts.foo)

def test_getitem(self):
idx1 = pd.timedelta_range('1 day', '31 day', freq='D', name='idx')

for idx in [idx1]:
result = idx[0]
self.assertEqual(result, pd.Timedelta('1 day'))

result = idx[0:5]
expected = pd.timedelta_range('1 day', '5 day', freq='D', name='idx')
self.assert_index_equal(result, expected)
self.assertEqual(result.freq, expected.freq)

result = idx[0:10:2]
expected = pd.timedelta_range('1 day', '9 day', freq='2D', name='idx')
self.assert_index_equal(result, expected)
self.assertEqual(result.freq, expected.freq)

result = idx[-20:-5:3]
expected = pd.timedelta_range('12 day', '25 day', freq='3D', name='idx')
self.assert_index_equal(result, expected)
self.assertEqual(result.freq, expected.freq)

result = idx[4::-1]
expected = TimedeltaIndex(['5 day', '4 day', '3 day', '2 day', '1 day'],
freq='-1D', name='idx')
self.assert_index_equal(result, expected)
self.assertEqual(result.freq, expected.freq)

class TestPeriodIndexOps(Ops):

Expand Down