Skip to content

Commit 3b0bb1f

Browse files
committed
ENH: Handle tuples shorter than nlevels gracefully
1 parent c958de7 commit 3b0bb1f

File tree

2 files changed

+39
-10
lines changed

2 files changed

+39
-10
lines changed

pandas/core/frame.py

+16-10
Original file line numberDiff line numberDiff line change
@@ -3032,21 +3032,27 @@ def _maybe_casted_values(index, labels=None):
30323032
if not drop:
30333033
multi_col = isinstance(self.columns, MultiIndex)
30343034
for i, (lev, lab) in reversed(list(enumerate(to_insert))):
3035-
col_name = names[i]
3036-
3037-
if multi_col and not isinstance(col_name, tuple):
3035+
name = names[i]
3036+
if multi_col:
3037+
col_name = (list(name) if isinstance(name, tuple)
3038+
else [name])
30383039
if col_fill is None:
3039-
col_name = tuple([col_name] * self.columns.nlevels)
3040-
else:
3041-
name_lst = [col_fill] * self.columns.nlevels
3042-
lev_num = self.columns._get_level_number(col_level)
3043-
name_lst[lev_num] = col_name
3044-
col_name = tuple(name_lst)
3040+
if len(col_name) not in (1, self.columns.nlevels):
3041+
raise ValueError("col_fill=None is incompatible "
3042+
"with incomplete column name "
3043+
"{}".format(name))
3044+
col_fill = col_name[0]
3045+
3046+
lev_num = self.columns._get_level_number(col_level)
3047+
name_lst = [col_fill] * lev_num + col_name
3048+
missing = self.columns.nlevels - len(name_lst)
3049+
name_lst += [col_fill] * missing
3050+
name = tuple(name_lst)
30453051

30463052
# to ndarray and maybe infer different dtype
30473053
level_values = _maybe_casted_values(lev, lab)
30483054
if level is None or i in level:
3049-
new_obj.insert(0, col_name, level_values)
3055+
new_obj.insert(0, name, level_values)
30503056

30513057
new_obj.index = new_index
30523058
if not inplace:

pandas/tests/test_multilevel.py

+23
Original file line numberDiff line numberDiff line change
@@ -2263,6 +2263,29 @@ def test_reset_index_multiindex_columns(self):
22632263
result = df.set_index([('B', 'b')], append=True).reset_index()
22642264
tm.assert_frame_equal(result, expected)
22652265

2266+
# with index name which is a too long tuple...
2267+
with tm.assert_raises_regex(ValueError,
2268+
("Item must have length equal to number "
2269+
"of levels.")):
2270+
df.rename_axis([('C', 'c', 'i')]).reset_index()
2271+
# or too short...
2272+
levels = [['A', 'a', ''], ['B', 'b', 'i']]
2273+
df2 = pd.DataFrame([[0, 2], [1, 3]],
2274+
columns=pd.MultiIndex.from_tuples(levels))
2275+
idx_col = pd.DataFrame([[0], [1]],
2276+
columns=pd.MultiIndex.from_tuples([('C',
2277+
'c',
2278+
'ii')]))
2279+
expected = pd.concat([idx_col, df2], axis=1)
2280+
result = df2.rename_axis([('C', 'c')]).reset_index(col_fill='ii')
2281+
tm.assert_frame_equal(result, expected)
2282+
2283+
# ... which is incompatible with col_fill=None
2284+
with tm.assert_raises_regex(ValueError,
2285+
("col_fill=None is incompatible with "
2286+
"incomplete column name \('C', 'c'\)")):
2287+
df2.rename_axis([('C', 'c')]).reset_index(col_fill=None)
2288+
22662289
def test_set_index_period(self):
22672290
# GH 6631
22682291
df = DataFrame(np.random.random(6))

0 commit comments

Comments
 (0)