pandas-dev / pandas

Flexible and powerful data analysis / manipulation library for Python, providing labeled data structures similar to R data.frame objects, statistical functions, and much more
https://pandas.pydata.org
BSD 3-Clause "New" or "Revised" License
43.49k stars 17.87k forks source link

BUG: pandas.read_excel creates a DataFrame with incorrect multi-level columns #34188

Open LastsForever opened 4 years ago

LastsForever commented 4 years ago

Note: Please read this guide detailing how to provide the necessary information for us to reproduce your bug.

There is a file a.xlsx with only index and multi-level columns:

image

pd.read_excel('a.xlsx', index_col=0, header=[0, 1]) creates a DataFrame with incorrect multi-level columns:

image

However, if the file b.xlsx with the same structure (shown below) is not empty, the result appears to be correct:

C559F1A1-36E2-4B1E-B6EF-8AD1EDAE7420 image

Problem description

The parameter header=[0, 1] indicates that the first two rows of the excel file should be used as multi-level columns, but the result got first three rows as the multi-level columns.

Expected Output

pd.read_excel('a.xlsx', index_col=0, header=[0, 1]) should get the DataFrame:

image

Output of pd.show_versions()

INSTALLED VERSIONS ------------------ commit : None python : 3.8.2.final.0 python-bits : 64 OS : Darwin OS-release : 19.4.0 machine : x86_64 processor : i386 byteorder : little LC_ALL : None LANG : None LOCALE : None.UTF-8 pandas : 1.0.3 numpy : 1.18.1 pytz : 2020.1 dateutil : 2.8.1 pip : 20.0.2 setuptools : 46.2.0.post20200511 Cython : None pytest : None hypothesis : None sphinx : None blosc : None feather : None xlsxwriter : None lxml.etree : None html5lib : None pymysql : None psycopg2 : None jinja2 : 2.11.2 IPython : 7.13.0 pandas_datareader: None bs4 : None bottleneck : None fastparquet : None gcsfs : None lxml.etree : None matplotlib : 3.1.3 numexpr : None odfpy : None openpyxl : 3.0.3 pandas_gbq : None pyarrow : None pytables : None pytest : None pyxlsb : None s3fs : None scipy : None sqlalchemy : None tables : None tabulate : None xarray : None xlrd : 1.2.0 xlwt : 1.3.0 xlsxwriter : None numba : None
rhshadrach commented 3 years ago

Thanks for the report! It seems writing might have a related issue. Doing:

df = pd.DataFrame({'a': 3 * [None]}, index=[1, 2, 3])
df.columns = pd.MultiIndex.from_arrays([['A'], ['x']])
df.to_excel('test.xlsx')

produces an empty line below the columns. Reading this in produces the original DataFrame correctly. If I first delete this empty line and then read in the excel file, I get the issue mentioned above.

ahawryluk commented 3 years ago

It looks like this behaviour was intentional. The reader interprets the blank spaces the same way the writer does, and "in the case of column MultiIndex a blank row ALWAYS has to be inserted so the format is unambiguous. I believe this is unavoidable (csv does it too) - but the output looks a little odd if the index doesn't have names." https://github.com/pandas-dev/pandas/pull/10967#issuecomment-137603832

Also, https://github.com/pandas-dev/pandas/pull/10967#issuecomment-137714842 points out this exact case as being ambiguous:

spreadsheet screenshot

There's no way to know if "a" is the index name or if the data row is blank. Pandas assumes that "a" is the index name because that's how it writes named MulitIndex dataframes.

rhshadrach commented 3 years ago

Thanks @ahawryluk. I don't see any options that would improve upon this, but perhaps a note in the documentation of read_excel may be useful.