diff --git a/doc/source/v0.14.1.txt b/doc/source/v0.14.1.txt index c6144619da963..e038124cadc00 100644 --- a/doc/source/v0.14.1.txt +++ b/doc/source/v0.14.1.txt @@ -166,7 +166,7 @@ Experimental Bug Fixes ~~~~~~~~~ - Bug in ``DataFrame.where`` with a symmetric shaped frame and a passed other of a DataFrame (:issue:`7506`) - +- Bug in Panel indexing with a multi-index axis (:issue:`7516`) - Bug in timeops with non-aligned Series (:issue:`7500`) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index cf9ff8abff3ef..214994a6fc185 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -1632,11 +1632,11 @@ def _reindex_axes(self, axes, level, limit, method, fill_value, copy): continue # convert to an index if we are not a multi-selection + ax = self._get_axis(a) if level is None: labels = _ensure_index(labels) axis = self._get_axis_number(a) - ax = self._get_axis(a) new_index, indexer = ax.reindex( labels, level=level, limit=limit, method=method) @@ -1929,11 +1929,11 @@ def _get_bool_data(self): def as_matrix(self, columns=None): """ - Convert the frame to its Numpy-array representation. - + Convert the frame to its Numpy-array representation. + Parameters ---------- - columns: list, optional, default:None + columns: list, optional, default:None If None, return all columns, otherwise, returns specified columns. Returns @@ -1942,23 +1942,23 @@ def as_matrix(self, columns=None): If the caller is heterogeneous and contains booleans or objects, the result will be of dtype=object. See Notes. - + Notes - ----- + ----- Return is NOT a Numpy-matrix, rather, a Numpy-array. - + The dtype will be a lower-common-denominator dtype (implicit upcasting); that is to say if the dtypes (even of numeric types) are mixed, the one that accommodates all will be chosen. Use this with care if you are not dealing with the blocks. - e.g. If the dtypes are float16 and float32, dtype will be upcast to - float32. If dtypes are int32 and uint8, dtype will be upcase to + e.g. If the dtypes are float16 and float32, dtype will be upcast to + float32. If dtypes are int32 and uint8, dtype will be upcase to int32. This method is provided for backwards compatibility. Generally, it is recommended to use '.values'. - + See Also -------- pandas.DataFrame.values @@ -1971,7 +1971,7 @@ def as_matrix(self, columns=None): @property def values(self): """Numpy representation of NDFrame - + Notes ----- The dtype will be a lower-common-denominator dtype (implicit @@ -1979,8 +1979,8 @@ def values(self): are mixed, the one that accommodates all will be chosen. Use this with care if you are not dealing with the blocks. - e.g. If the dtypes are float16 and float32, dtype will be upcast to - float32. If dtypes are int32 and uint8, dtype will be upcase to + e.g. If the dtypes are float16 and float32, dtype will be upcast to + float32. If dtypes are int32 and uint8, dtype will be upcase to int32. """ return self.as_matrix() diff --git a/pandas/core/indexing.py b/pandas/core/indexing.py index bfff85ac4712c..0c695a0c2d632 100644 --- a/pandas/core/indexing.py +++ b/pandas/core/indexing.py @@ -816,7 +816,7 @@ def _getitem_nested_tuple(self, tup): # this is iterative obj = self.obj axis = 0 - for key in tup: + for i, key in enumerate(tup): if _is_null_slice(key): axis += 1 @@ -833,6 +833,13 @@ def _getitem_nested_tuple(self, tup): # has the dim of the obj changed? # GH 7199 if obj.ndim < current_ndim: + + # GH 7516 + # if had a 3 dim and are going to a 2d + # axes are reversed on a DataFrame + if i >= 1 and current_ndim == 3 and obj.ndim == 2: + obj = obj.T + axis -= 1 return obj diff --git a/pandas/core/panel.py b/pandas/core/panel.py index 757bef0d1526d..23115999d074f 100644 --- a/pandas/core/panel.py +++ b/pandas/core/panel.py @@ -797,12 +797,15 @@ def _ixs(self, i, axis=0): axis : int """ - key = self._get_axis(axis)[i] + ax = self._get_axis(axis) + key = ax[i] # xs cannot handle a non-scalar key, so just reindex here - if _is_list_like(key): - indexer = {self._get_axis_name(axis): key} - return self.reindex(**indexer) + # if we have a multi-index and a single tuple, then its a reduction (GH 7516) + if not (isinstance(ax, MultiIndex) and isinstance(key, tuple)): + if _is_list_like(key): + indexer = {self._get_axis_name(axis): key} + return self.reindex(**indexer) # a reduction if axis == 0: diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py index cd569deac2ceb..4ee6bd1d949a5 100644 --- a/pandas/tests/test_indexing.py +++ b/pandas/tests/test_indexing.py @@ -1179,6 +1179,16 @@ def f(): result2 = wd2.iloc[0,[0],[0,1,2]] assert_frame_equal(result2,expected2) + # GH 7516 + mi = MultiIndex.from_tuples([(0,'x'), (1,'y'), (2,'z')]) + p = Panel(np.arange(3*3*3,dtype='int64').reshape(3,3,3), items=['a','b','c'], major_axis=mi, minor_axis=['u','v','w']) + result = p.iloc[:, 1, 0] + expected = Series([3,12,21],index=['a','b','c'], name='u') + assert_series_equal(result,expected) + + result = p.loc[:, (1,'y'), 'u'] + assert_series_equal(result,expected) + def test_iloc_getitem_doc_issue(self): # multi axis slicing issue with single block