Skip to content

Commit 5fc66c3

Browse files
committed
make map return an index if it operates on an index, multi index, or categorical index; map on a categorical will either return a categorical or an index (rather than a numpy array)
1 parent 3ba2cff commit 5fc66c3

File tree

6 files changed

+54
-31
lines changed

6 files changed

+54
-31
lines changed

pandas/core/categorical.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -943,7 +943,7 @@ def map(self, mapper):
943943
944944
Returns
945945
-------
946-
applied : Categorical or np.ndarray.
946+
applied : Categorical or Index.
947947
"""
948948
new_categories = self.categories.map(mapper)
949949
try:

pandas/indexes/base.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -2428,7 +2428,7 @@ def groupby(self, values):
24282428

24292429
def map(self, mapper):
24302430
"""
2431-
Apply mapper function to its values.
2431+
Apply mapper function to an index.
24322432
24332433
Parameters
24342434
----------
@@ -2437,9 +2437,12 @@ def map(self, mapper):
24372437
24382438
Returns
24392439
-------
2440-
applied : array
2440+
applied : Index
2441+
The output of the mapping function applied to the index.
24412442
"""
2442-
return self._arrmap(self.values, mapper)
2443+
attributes = self._get_attributes_dict()
2444+
attributes['copy'] = False
2445+
return Index(self._arrmap(self.values, mapper), **attributes)
24432446

24442447
def isin(self, values, level=None):
24452448
"""

pandas/indexes/category.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -524,15 +524,15 @@ def map(self, mapper):
524524
----------
525525
mapper : callable
526526
Function to be applied. When all categories are mapped
527-
to different categories, the result will be Categorical which has
528-
the same order property as the original. Otherwise, the result will
529-
be np.ndarray.
527+
to different categories, the result will be a CategoricalIndex
528+
which has the same order property as the original. Otherwise,
529+
the result will be a Index.
530530
531531
Returns
532532
-------
533-
applied : Categorical or np.ndarray.
533+
applied : CategoricalIndex or Index
534534
"""
535-
return self.values.map(mapper)
535+
return self._shallow_copy_with_infer(self.values.map(mapper))
536536

537537
def delete(self, loc):
538538
"""

pandas/tests/indexes/test_base.py

+30-10
Original file line numberDiff line numberDiff line change
@@ -767,6 +767,26 @@ def test_sub(self):
767767
self.assertRaises(TypeError, lambda: idx - idx.tolist())
768768
self.assertRaises(TypeError, lambda: idx.tolist() - idx)
769769

770+
def test_map_identity_mapping(self):
771+
for name, cur_index in self.indices.items():
772+
if name == 'tuples':
773+
expected = Index(cur_index.values, tupleize_cols=False)
774+
self.assert_index_equal(expected, cur_index.map(lambda x: x))
775+
else:
776+
self.assert_index_equal(cur_index, cur_index.map(lambda x: x))
777+
778+
def test_map_that_returns_tuples_creates_index_not_multi_index(self):
779+
boolean_index = tm.makeIntIndex(3).map(lambda x: (x, x == 1))
780+
expected = Index([(0, False), (1, True), (2, False)],
781+
tupleize_cols=False)
782+
self.assert_index_equal(boolean_index, expected)
783+
784+
def test_map_that_reduces_multi_index_to_single_index_returns_index(self):
785+
first_level = ['foo', 'bar', 'baz']
786+
multi_index = MultiIndex.from_tuples(lzip(first_level, [1, 2, 3]))
787+
reduced_index = multi_index.map(lambda x: x[0])
788+
self.assert_index_equal(reduced_index, Index(first_level))
789+
770790
def test_append_multiple(self):
771791
index = Index(['a', 'b', 'c', 'd', 'e', 'f'])
772792

@@ -1194,16 +1214,16 @@ def check_slice(in_slice, expected):
11941214
self.assert_index_equal(result, expected)
11951215

11961216
for in_slice, expected in [
1197-
(SLC[::-1], 'yxdcb'), (SLC['b':'y':-1], ''),
1198-
(SLC['b'::-1], 'b'), (SLC[:'b':-1], 'yxdcb'),
1199-
(SLC[:'y':-1], 'y'), (SLC['y'::-1], 'yxdcb'),
1200-
(SLC['y'::-4], 'yb'),
1201-
# absent labels
1202-
(SLC[:'a':-1], 'yxdcb'), (SLC[:'a':-2], 'ydb'),
1203-
(SLC['z'::-1], 'yxdcb'), (SLC['z'::-3], 'yc'),
1204-
(SLC['m'::-1], 'dcb'), (SLC[:'m':-1], 'yx'),
1205-
(SLC['a':'a':-1], ''), (SLC['z':'z':-1], ''),
1206-
(SLC['m':'m':-1], '')
1217+
(SLC[::-1], 'yxdcb'), (SLC['b':'y':-1], ''),
1218+
(SLC['b'::-1], 'b'), (SLC[:'b':-1], 'yxdcb'),
1219+
(SLC[:'y':-1], 'y'), (SLC['y'::-1], 'yxdcb'),
1220+
(SLC['y'::-4], 'yb'),
1221+
# absent labels
1222+
(SLC[:'a':-1], 'yxdcb'), (SLC[:'a':-2], 'ydb'),
1223+
(SLC['z'::-1], 'yxdcb'), (SLC['z'::-3], 'yc'),
1224+
(SLC['m'::-1], 'dcb'), (SLC[:'m':-1], 'yx'),
1225+
(SLC['a':'a':-1], ''), (SLC['z':'z':-1], ''),
1226+
(SLC['m':'m':-1], '')
12071227
]:
12081228
check_slice(in_slice, expected)
12091229

pandas/tests/indexes/test_category.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -207,19 +207,19 @@ def test_map(self):
207207
ci = pd.CategoricalIndex(list('ABABC'), categories=list('CBA'),
208208
ordered=True)
209209
result = ci.map(lambda x: x.lower())
210-
exp = pd.Categorical(list('ababc'), categories=list('cba'),
211-
ordered=True)
212-
tm.assert_categorical_equal(result, exp)
210+
exp = pd.CategoricalIndex(list('ababc'), categories=list('cba'),
211+
ordered=True)
212+
tm.assert_index_equal(result, exp)
213213

214214
ci = pd.CategoricalIndex(list('ABABC'), categories=list('BAC'),
215215
ordered=False, name='XXX')
216216
result = ci.map(lambda x: x.lower())
217-
exp = pd.Categorical(list('ababc'), categories=list('bac'),
218-
ordered=False)
219-
tm.assert_categorical_equal(result, exp)
217+
exp = pd.CategoricalIndex(list('ababc'), categories=list('bac'),
218+
ordered=False, name='XXX')
219+
tm.assert_index_equal(result, exp)
220220

221-
tm.assert_numpy_array_equal(ci.map(lambda x: 1),
222-
np.array([1] * 5, dtype=np.int64))
221+
tm.assert_index_equal(ci.map(lambda x: 1),
222+
Index(np.array([1] * 5, dtype=np.int64), name='XXX'))
223223

224224
# change categories dtype
225225
ci = pd.CategoricalIndex(list('ABABC'), categories=list('BAC'),
@@ -228,9 +228,9 @@ def f(x):
228228
return {'A': 10, 'B': 20, 'C': 30}.get(x)
229229

230230
result = ci.map(f)
231-
exp = pd.Categorical([10, 20, 10, 20, 30], categories=[20, 10, 30],
232-
ordered=False)
233-
tm.assert_categorical_equal(result, exp)
231+
exp = pd.CategoricalIndex([10, 20, 10, 20, 30], categories=[20, 10, 30],
232+
ordered=False)
233+
tm.assert_index_equal(result, exp)
234234

235235
def test_where(self):
236236
i = self.create_index()

pandas/tests/test_categorical.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1669,7 +1669,7 @@ def test_map(self):
16691669
tm.assert_categorical_equal(result, exp)
16701670

16711671
result = c.map(lambda x: 1)
1672-
tm.assert_numpy_array_equal(result, np.array([1] * 5, dtype=np.int64))
1672+
tm.assert_index_equal(result, Index(np.array([1] * 5, dtype=np.int64)))
16731673

16741674

16751675
class TestCategoricalAsBlock(tm.TestCase):

0 commit comments

Comments
 (0)