diff --git a/pandas/io/formats/excel.py b/pandas/io/formats/excel.py index 98f7b64d2cda0..f11127eb97dd9 100644 --- a/pandas/io/formats/excel.py +++ b/pandas/io/formats/excel.py @@ -647,7 +647,9 @@ def _format_header_mi(self) -> Iterable[ExcelCell]: for lnum, (spans, levels, level_codes) in enumerate( zip(level_lengths, columns.levels, columns.codes) ): - values = levels.take(level_codes) + values = levels.take( + level_codes, fill_value=self.na_rep if -1 in level_codes else None + ) for i, span_val in spans.items(): mergestart, mergeend = None, None if span_val > 1: diff --git a/pandas/tests/io/excel/test_writers.py b/pandas/tests/io/excel/test_writers.py index 9a8e4eff5470a..6c27daf3d56ca 100644 --- a/pandas/tests/io/excel/test_writers.py +++ b/pandas/tests/io/excel/test_writers.py @@ -792,6 +792,28 @@ def test_to_excel_multiindex_cols(self, merge_cells, frame, path): frame.columns = [".".join(map(str, q)) for q in zip(*fm)] tm.assert_frame_equal(frame, df) + @pytest.mark.xfail(reason="na_values aren't applied to Index") + def test_to_excel_multiindex_nan_level(self, frame, path): + """ + Tests https://github.com/pandas-dev/pandas/issues/51252 + """ + cols_index = MultiIndex.from_tuples( + [ + ("Item", "Type 1", "Class A"), + ("Item", "Type 1", "Class B"), + ("Item", "Type 2", "Class A"), + ("Item", "Type 2", "Class B"), + ("Item", "Type 3", None), + ] + ) + df = pd.DataFrame(np.random.randn(10, 5), columns=cols_index) + df.to_excel(path, "test1") + with ExcelFile(path) as reader: + df2 = pd.read_excel( + reader, sheet_name="test1", header=[0, 1, 2], index_col=[0] + ) + tm.assert_frame_equal(df, df2) + def test_to_excel_multiindex_dates(self, merge_cells, tsframe, path): # try multiindex with dates new_index = [tsframe.index, np.arange(len(tsframe.index), dtype=np.int64)]