From 4e8674871d756c441bd762710857f137a2b72dae Mon Sep 17 00:00:00 2001 From: Wes McKinney Date: Wed, 22 Jun 2011 23:23:07 -0400 Subject: [PATCH] added missing Series.ix case for completeness, optimized DataFrame.ix[...] to reduce unnecessary computation in some cases --- pandas/core/common.py | 2 +- pandas/core/frame.py | 18 +++++++++++++----- pandas/core/series.py | 16 ++++++++++------ pandas/core/tests/test_frame.py | 4 ++++ pandas/core/tests/test_series.py | 10 ++++++++++ test.sh | 4 ++-- 6 files changed, 40 insertions(+), 14 deletions(-) diff --git a/pandas/core/common.py b/pandas/core/common.py index 0204be6f8fad3..f427ea0e6de7e 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -121,7 +121,7 @@ def _need_slice(obj): return obj.start is not None or obj.stop is not None def _check_step(obj): - if obj.step is not None: + if obj.step is not None and obj.step != 1: raise Exception('steps other than 1 are not supported') def _ensure_index(index_like): diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 3231f4d4ada9a..159508264ec1d 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2478,12 +2478,20 @@ def _fancy_getitem(self, key, axis=0): return self.reindex(**{axis_name : key}) def _fancy_getitem_tuple(self, rowkey, colkey): - result = self._fancy_getitem_axis(colkey, axis=1) + def _is_label_like(key): + # select a label or row + return not isinstance(key, slice) and not _is_list_like(key) + + # to avoid wasted computation + # df.ix[d1:d2, 0] -> columns first (True) + # df.ix[0, ['C', 'B', A']] -> rows first (False) + if _is_label_like(colkey): + return self._fancy_getitem_axis(colkey, axis=1).ix[rowkey] + elif _is_label_like(rowkey): + return self._fancy_getitem_axis(rowkey, axis=0).ix[colkey] - if isinstance(result, Series): - result = result[rowkey] - else: - result = result._fancy_getitem_axis(rowkey, axis=0) + result = self._fancy_getitem_axis(colkey, axis=1) + result = result._fancy_getitem_axis(rowkey, axis=0) return result diff --git a/pandas/core/series.py b/pandas/core/series.py index b49f216e6cba7..cdefc72085979 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -3,7 +3,7 @@ """ # pylint: disable=E1101,E1103 -# pylint: disable=W0703,W0622 +# pylint: disable=W0703,W0622,W0613 import itertools import operator @@ -14,12 +14,12 @@ import numpy as np from pandas.core.common import isnull, notnull -from pandas.core.common import (_check_step, _need_slice, _is_label_slice, - _ensure_index) +from pandas.core.common import (_need_slice, _is_label_slice, + _is_list_like, _ensure_index) from pandas.core.daterange import DateRange from pandas.core.generic import PandasGeneric -from pandas.core.index import Index, NULL_INDEX +from pandas.core.index import Index import pandas.core.datetools as datetools import pandas.lib.tseries as tseries @@ -1376,8 +1376,10 @@ def _fancy_getitem(self, key): return self[i:j] else: return self[key] - else: + elif _is_list_like(key): return self.reindex(key) + else: + return self[key] def _fancy_setitem(self, key, value): if _isboolarr(key): @@ -1392,11 +1394,13 @@ def _fancy_setitem(self, key, value): self[i:j] = value else: self[key] = value - else: + elif _is_list_like(key): inds, mask = self.index.get_indexer(key) if not mask.all(): raise Exception('Indices %s not found' % key[-mask]) self.put(inds, value) + else: + self[key] = value class TimeSeries(Series): pass diff --git a/pandas/core/tests/test_frame.py b/pandas/core/tests/test_frame.py index 412a4926f0abc..4c7e084115cc6 100644 --- a/pandas/core/tests/test_frame.py +++ b/pandas/core/tests/test_frame.py @@ -181,6 +181,10 @@ def test_getitem_fancy_2d(self): assert_frame_equal(ix[:, ['B', 'A']], f.reindex(columns=['B', 'A'])) + subidx = self.frame.index[[5, 4, 1]] + assert_frame_equal(ix[subidx, ['B', 'A']], + f.reindex(index=subidx, columns=['B', 'A'])) + # slicing rows, etc. assert_frame_equal(ix[5:10], f[5:10]) assert_frame_equal(ix[5:10, :], f[5:10]) diff --git a/pandas/core/tests/test_series.py b/pandas/core/tests/test_series.py index 90ae0fb44a659..1b5ac4c835736 100644 --- a/pandas/core/tests/test_series.py +++ b/pandas/core/tests/test_series.py @@ -248,6 +248,10 @@ def test_ix_getitem(self): mask = self.series > self.series.median() assert_series_equal(self.series.ix[mask], self.series[mask]) + # ask for index value + self.assertEquals(self.series.ix[d1], self.series[d1]) + self.assertEquals(self.series.ix[d2], self.series[d2]) + def test_ix_setitem(self): inds = self.series.index[[3,4,7]] @@ -268,6 +272,12 @@ def test_ix_setitem(self): expected[5:16] = 6 # because it's inclusive assert_series_equal(result, expected) + # set index value + self.series.ix[d1] = 4 + self.series.ix[d2] = 6 + self.assertEquals(self.series[d1], 4) + self.assertEquals(self.series[d2], 6) + def test_ix_setitem_boolean(self): mask = self.series > self.series.median() diff --git a/test.sh b/test.sh index 66e3d2014a8fe..5b162f97d195c 100755 --- a/test.sh +++ b/test.sh @@ -1,7 +1,7 @@ #!/bin/sh coverage erase # nosetests -w pandas --with-coverage --cover-package=pandas --pdb-failure --pdb -nosetests -w pandas/io --with-coverage --cover-package=pandas.io --pdb-failure --pdb -# nosetests -w pandas/core --with-coverage --cover-package=pandas.core --pdb-failure --pdb +# nosetests -w pandas/io --with-coverage --cover-package=pandas.io --pdb-failure --pdb +nosetests -w pandas/core --with-coverage --cover-package=pandas.core --pdb-failure --pdb # nosetests -w pandas/stats --with-coverage --cover-package=pandas.stats # coverage run runtests.py \ No newline at end of file