Skip to content

Commit 59cc3dd

Browse files
API: re-allow duplicate index level names
1 parent 7000b89 commit 59cc3dd

File tree

5 files changed

+39
-39
lines changed

5 files changed

+39
-39
lines changed

Diff for: pandas/core/indexes/multi.py

-12
Original file line numberDiff line numberDiff line change
@@ -672,30 +672,18 @@ def _set_names(self, names, level=None, validate=True):
672672

673673
if level is None:
674674
level = range(self.nlevels)
675-
used = {}
676675
else:
677676
level = [self._get_level_number(l) for l in level]
678-
used = {self.levels[l].name: l
679-
for l in set(range(self.nlevels)) - set(level)}
680677

681678
# set the name
682679
for l, name in zip(level, names):
683680
if name is not None:
684-
685681
# GH 20527
686682
# All items in 'names' need to be hashable:
687683
if not is_hashable(name):
688684
raise TypeError('{}.name must be a hashable type'
689685
.format(self.__class__.__name__))
690-
691-
if name in used:
692-
raise ValueError(
693-
'Duplicated level name: "{}", assigned to '
694-
'level {}, is already used for level '
695-
'{}.'.format(name, l, used[name]))
696-
697686
self.levels[l].rename(name, inplace=True)
698-
used[name] = l
699687

700688
names = property(fset=_set_names, fget=_get_names,
701689
doc="Names of levels in MultiIndex")

Diff for: pandas/tests/frame/test_alter_axes.py

+10-5
Original file line numberDiff line numberDiff line change
@@ -130,19 +130,24 @@ def test_set_index2(self):
130130
result = df.set_index(df.C)
131131
assert result.index.name == 'C'
132132

133-
@pytest.mark.parametrize('level', ['a', pd.Series(range(3), name='a')])
133+
@pytest.mark.parametrize(
134+
'level', ['a', pd.Series(range(0, 8, 2), name='a')])
134135
def test_set_index_duplicate_names(self, level):
135-
# GH18872
136+
# GH18872 - GH19029
136137
df = pd.DataFrame(np.arange(8).reshape(4, 2), columns=['a', 'b'])
137138

138139
# Pass an existing level name:
139140
df.index.name = 'a'
140-
pytest.raises(ValueError, df.set_index, level, append=True)
141-
pytest.raises(ValueError, df.set_index, [level], append=True)
141+
expected = pd.MultiIndex.from_tuples([(0, 0), (1, 2), (2, 4), (3, 6)],
142+
names=['a', 'a'])
143+
result = df.set_index(level, append=True)
144+
tm.assert_index_equal(result.index, expected)
145+
result = df.set_index([level], append=True)
146+
tm.assert_index_equal(result.index, expected)
142147

143148
# Pass twice the same level name:
144149
df.index.name = 'c'
145-
pytest.raises(ValueError, df.set_index, [level, level])
150+
# pytest.raises(ValueError, df.set_index, [level, level])
146151

147152
def test_set_index_nonuniq(self):
148153
df = DataFrame({'A': ['foo', 'foo', 'foo', 'bar', 'bar'],

Diff for: pandas/tests/groupby/test_categorical.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -553,14 +553,14 @@ def test_as_index():
553553
columns=['cat', 'A', 'B'])
554554
tm.assert_frame_equal(result, expected)
555555

556-
# another not in-axis grouper
557-
s = Series(['a', 'b', 'b'], name='cat2')
556+
# another not in-axis grouper (conflicting names in index)
557+
s = Series(['a', 'b', 'b'], name='cat')
558558
result = df.groupby(['cat', s], as_index=False, observed=True).sum()
559559
tm.assert_frame_equal(result, expected)
560560

561-
# GH18872: conflicting names in desired index
562-
with pytest.raises(ValueError):
563-
df.groupby(['cat', s.rename('cat')], observed=True).sum()
561+
# # GH18872: conflicting names in desired index
562+
# with pytest.raises(ValueError):
563+
# df.groupby(['cat', s.rename('cat')], observed=True).sum()
564564

565565
# is original index dropped?
566566
group_columns = ['cat', 'A']

Diff for: pandas/tests/indexes/test_multi.py

+16-16
Original file line numberDiff line numberDiff line change
@@ -656,22 +656,22 @@ def test_constructor_nonhashable_names(self):
656656
# With .set_names()
657657
tm.assert_raises_regex(TypeError, message, mi.set_names, names=renamed)
658658

659-
@pytest.mark.parametrize('names', [['a', 'b', 'a'], ['1', '1', '2'],
660-
['1', 'a', '1']])
661-
def test_duplicate_level_names(self, names):
662-
# GH18872
663-
pytest.raises(ValueError, pd.MultiIndex.from_product,
664-
[[0, 1]] * 3, names=names)
665-
666-
# With .rename()
667-
mi = pd.MultiIndex.from_product([[0, 1]] * 3)
668-
tm.assert_raises_regex(ValueError, "Duplicated level name:",
669-
mi.rename, names)
670-
671-
# With .rename(., level=)
672-
mi.rename(names[0], level=1, inplace=True)
673-
tm.assert_raises_regex(ValueError, "Duplicated level name:",
674-
mi.rename, names[:2], level=[0, 2])
659+
# @pytest.mark.parametrize('names', [['a', 'b', 'a'], ['1', '1', '2'],
660+
# ['1', 'a', '1']])
661+
# def test_duplicate_level_names(self, names):
662+
# # GH18872
663+
# pytest.raises(ValueError, pd.MultiIndex.from_product,
664+
# [[0, 1]] * 3, names=names)
665+
666+
# # With .rename()
667+
# mi = pd.MultiIndex.from_product([[0, 1]] * 3)
668+
# tm.assert_raises_regex(ValueError, "Duplicated level name:",
669+
# mi.rename, names)
670+
671+
# # With .rename(., level=)
672+
# mi.rename(names[0], level=1, inplace=True)
673+
# tm.assert_raises_regex(ValueError, "Duplicated level name:",
674+
# mi.rename, names[:2], level=[0, 2])
675675

676676
def assert_multiindex_copied(self, copy, original):
677677
# Levels should be (at least, shallow copied)

Diff for: pandas/tests/reshape/test_pivot.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -1729,10 +1729,17 @@ def test_crosstab_with_numpy_size(self):
17291729
tm.assert_frame_equal(result, expected)
17301730

17311731
def test_crosstab_dup_index_names(self):
1732-
# GH 13279, GH 18872
1732+
# GH 13279
17331733
s = pd.Series(range(3), name='foo')
17341734
pytest.raises(ValueError, pd.crosstab, s, s)
17351735

1736+
result = pd.crosstab(s, s)
1737+
expected_index = pd.Index(range(3), name='foo')
1738+
expected = pd.DataFrame(np.eye(3, dtype=np.int64),
1739+
index=expected_index,
1740+
columns=expected_index)
1741+
tm.assert_frame_equal(result, expected)
1742+
17361743
@pytest.mark.parametrize("names", [['a', ('b', 'c')],
17371744
[('a', 'b'), 'c']])
17381745
def test_crosstab_tuple_name(self, names):

0 commit comments

Comments
 (0)