diff --git a/doc/source/whatsnew/v0.17.0.txt b/doc/source/whatsnew/v0.17.0.txt index 2e03cbbea2f70..ec575d06e82f2 100644 --- a/doc/source/whatsnew/v0.17.0.txt +++ b/doc/source/whatsnew/v0.17.0.txt @@ -124,8 +124,8 @@ Bug Fixes - Bug in ``test_categorical`` on big-endian builds (:issue:`10425`) - - +- Bug in ``Series.map`` using categorical ``Series`` raises ``AttributeError`` (:issue:`10324`) +- Bug in ``MultiIndex.get_level_values`` including ``Categorical`` raises ``AttributeError`` (:issue:`10460`) - Bug that caused segfault when resampling an empty Series (:issue:`10228`) - Bug in ``DatetimeIndex`` and ``PeriodIndex.value_counts`` resets name from its result, but retains in result's ``Index``. (:issue:`10150`) diff --git a/pandas/core/common.py b/pandas/core/common.py index 62721587e0828..773ecea8f2712 100644 --- a/pandas/core/common.py +++ b/pandas/core/common.py @@ -782,6 +782,11 @@ def take_nd(arr, indexer, axis=0, out=None, fill_value=np.nan, will be done. This short-circuits computation of a mask. Result is undefined if allow_fill == False and -1 is present in indexer. """ + + if is_categorical(arr): + return arr.take_nd(indexer, fill_value=fill_value, + allow_fill=allow_fill) + if indexer is None: indexer = np.arange(arr.shape[axis], dtype=np.int64) dtype, fill_value = arr.dtype, arr.dtype.type() diff --git a/pandas/tests/test_groupby.py b/pandas/tests/test_groupby.py index c6eb99985dc60..a327233e09003 100644 --- a/pandas/tests/test_groupby.py +++ b/pandas/tests/test_groupby.py @@ -3476,6 +3476,13 @@ def test_groupby_categorical(self): expected.index.names = ['myfactor', None] assert_frame_equal(desc_result, expected) + # GH 10460 + expc = Categorical.from_codes(np.arange(4).repeat(8), levels, name='myfactor', ordered=True) + exp = CategoricalIndex(expc, name='myfactor') + self.assert_index_equal(desc_result.index.get_level_values(0), exp) + exp = Index(['count', 'mean', 'std', 'min', '25%', '50%', '75%', 'max'] * 4) + self.assert_index_equal(desc_result.index.get_level_values(1), exp) + def test_groupby_datetime_categorical(self): # GH9049: ensure backward compatibility levels = pd.date_range('2014-01-01', periods=4) @@ -3488,7 +3495,8 @@ def test_groupby_datetime_categorical(self): expected = data.groupby(np.asarray(cats)).mean() expected = expected.reindex(levels) - expected.index = CategoricalIndex(expected.index,categories=expected.index,name='myfactor',ordered=True) + expected.index = CategoricalIndex(expected.index, categories=expected.index, + name='myfactor', ordered=True) assert_frame_equal(result, expected) self.assertEqual(result.index.name, cats.name) @@ -3503,6 +3511,14 @@ def test_groupby_datetime_categorical(self): expected.index.names = ['myfactor', None] assert_frame_equal(desc_result, expected) + # GH 10460 + expc = Categorical.from_codes(np.arange(4).repeat(8), levels, name='myfactor', ordered=True) + exp = CategoricalIndex(expc, name='myfactor') + self.assert_index_equal(desc_result.index.get_level_values(0), exp) + exp = Index(['count', 'mean', 'std', 'min', '25%', '50%', '75%', 'max'] * 4) + self.assert_index_equal(desc_result.index.get_level_values(1), exp) + + def test_groupby_categorical_index(self): levels = ['foo', 'bar', 'baz', 'qux'] diff --git a/pandas/tests/test_index.py b/pandas/tests/test_index.py index d84c813b2b898..a69db34bdd2df 100644 --- a/pandas/tests/test_index.py +++ b/pandas/tests/test_index.py @@ -3534,6 +3534,16 @@ def test_get_level_values(self): expected = self.index.get_level_values(0) self.assert_numpy_array_equal(result, expected) + # GH 10460 + index = MultiIndex(levels=[CategoricalIndex(['A', 'B']), + CategoricalIndex([1, 2, 3])], + labels=[np.array([0, 0, 0, 1, 1, 1]), + np.array([0, 1, 2, 0, 1, 2])]) + exp = CategoricalIndex(['A', 'A', 'A', 'B', 'B', 'B']) + self.assert_index_equal(index.get_level_values(0), exp) + exp = CategoricalIndex([1, 2 ,3, 1, 2, 3]) + self.assert_index_equal(index.get_level_values(1), exp) + def test_get_level_values_na(self): arrays = [['a', 'b', 'b'], [1, np.nan, 2]] index = pd.MultiIndex.from_arrays(arrays) diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py index 1e6fa68f1c85b..f3626488301b9 100644 --- a/pandas/tests/test_series.py +++ b/pandas/tests/test_series.py @@ -5753,6 +5753,35 @@ def test_map(self): result = self.ts.map(lambda x: x * 2) self.assert_numpy_array_equal(result, self.ts * 2) + # GH 10324 + a = Series([1, 2, 3, 4]) + b = Series(["even", "odd", "even", "odd"], dtype="category") + c = Series(["even", "odd", "even", "odd"]) + + exp = Series(["odd", "even", "odd", np.nan], dtype="category") + self.assert_series_equal(a.map(b), exp) + exp = Series(["odd", "even", "odd", np.nan]) + self.assert_series_equal(a.map(c), exp) + + a = Series(['a', 'b', 'c', 'd']) + b = Series([1, 2, 3, 4], index=pd.CategoricalIndex(['b', 'c', 'd', 'e'])) + c = Series([1, 2, 3, 4], index=Index(['b', 'c', 'd', 'e'])) + + exp = Series([np.nan, 1, 2, 3]) + self.assert_series_equal(a.map(b), exp) + exp = Series([np.nan, 1, 2, 3]) + self.assert_series_equal(a.map(c), exp) + + a = Series(['a', 'b', 'c', 'd']) + b = Series(['B', 'C', 'D', 'E'], dtype='category', + index=pd.CategoricalIndex(['b', 'c', 'd', 'e'])) + c = Series(['B', 'C', 'D', 'E'], index=Index(['b', 'c', 'd', 'e'])) + + exp = Series([np.nan, 'B', 'C', 'D'], dtype='category') + self.assert_series_equal(a.map(b), exp) + exp = Series([np.nan, 'B', 'C', 'D']) + self.assert_series_equal(a.map(c), exp) + def test_map_compat(self): # related GH 8024 s = Series([True,True,False],index=[1,2,3])