headers 下面的空白行是在 Python 中使用 MultiIndex 和 to_excel 时创建的
Blank line below headers created when using MultiIndex and to_excel in Python
我正在尝试使用 XlsxWriter 的 to_excel 函数将 Pandas 数据帧保存到 excel 文件。
当我将数据帧打印到终端时,它会正常读取,但是当我将它保存到 excel 并打开文件时,headers 下面有一个额外的空行不应该在那里。只有在 headers 使用 MultiIndex 时才会发生这种情况,但我需要它提供的分层 headers,但我找不到解决方案。
下面是来自在线 MultiIndex 示例的代码,它产生的结果与我正在处理的项目相同。任何解决方案将不胜感激。
import numpy as np
import pandas as pd
import xlsxwriter
tuples = [('bar', 'one'), ('bar', 'two'), ('baz', 'one'), ('baz', 'two'), ('foo', 'one'), ('foo', 'two'), ('qux', 'one'), ('qux', 'two')]
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
iterables = [['bar', 'baz', 'foo', 'qux'], ['one', 'two']]
pd.MultiIndex.from_product(iterables, names=['first', 'second'])
df = pd.DataFrame(np.random.randn(3, 8), index=['A', 'B', 'C'], columns=index)
print(df)
writer = pd.ExcelWriter('test.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='test1')
excel 输出创建:
这很可能是 pandas 中的错误。
有关建议的解决方案,请参阅 :
No easy way out of this but to delete that row by reading the xlsx in
again.
还有一个link进入GitHub issue,解决这个问题。
所以我做了这个解决方法,它可能对你有帮助:
df = pd.read_excel('/home/teoretic/test.xlsx', index_col=0)
df = df.drop(np.nan) # <== dropping an empty row
rename_dct = dict.fromkeys(df.loc[:,df.columns.str.contains('^Unnamed')], '')
df = df.rename(columns=rename_dct) # <== renaming 'Unnamed' columns to blank space
writer = pd.ExcelWriter('/home/teoretic/test_new.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='test1')
writer.close()
这是一个输出文件:
非常感谢这个问题和@Teoretic 的解决方法。
但是在我的例子中,Multiindex
列的合并单元格非常有用,而那些在@Teoretic 中丢失了。我已经做了一个替代解决方法,在写入之前隐藏整行,它有效,因此我将它包含在这里以防对任何人有用。
writer = pd.ExcelWriter('test.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='test1')
writer.sheets['test1'].set_row(2, None, None, {'hidden': True})
writer.save()
我找到了以下使用包 openpyxl 的解决方法,方法是读取包含空行的文件,删除该行,然后 re-writing 文件。我发现这种方法的优点是它保留了 MultiIndex 列中漂亮的合并单元格,实际上从 Excel 文件中删除了空行。通过实际删除空行,如果您的其余数据是数字,这将允许您在电子表格中开箱即用地使用 Excel 的过滤功能,而无需手动删除文件中的空行。
# Assuming df is your data frame with MultiIndex columns that you have already written to Excel
# Load the file with the empty line and select the sheet you want to edit
wb = openpyxl.load_workbook(filename = 'file_with_empty_line.xlsx')
ws = wb['sheet_name_to_edit']
# The row number to delete is 1-indexed in Excel
row_to_delete = df.columns.nlevels
ws.delete_rows(row_to_delete)
# If you want to write the name of the index into the empty cell above the index col
# after deleting the row (assuming you are writing to the first column):
ws['A'+str(row_to_delete)]=df.index.name
# Save the modified workbook to file
wb.save(filename = 'file_without_emtpy_line.xlsx')
虽然必须导入整个包来处理这个问题并不理想,但我的用例要求我不能简单地隐藏丢失的行。 @lrnzcig 的解决方案要好得多,如果你只需要隐藏空行就可以摆脱困境。
我用 ExcelWriter 删除了那个空行。我正在将 df 添加到现有的 sheet.
with pd.ExcelWriter(“PATH_TO_EXCEL”,mode=“a”,engine=“openpyxl”) as writer:
writer.book=load_workbook(“PATH_TO_EXCEL”)
df.to_excel(writer,sheet_name=“sample”,startrow=0,startcol=0)
writer.sheets[‘sample’].delete_rows(3)
我还有一个解决办法。它基于在 to_excel
函数的两次调用中保存的想法 - 第一次只保存 header,第二次保存 table 没有 header。为了实现我准备了这样的功能:
def save_double_column_df(df, xl_writer, startrow = 0, **kwargs):
'''Function to save doublecolumn DataFrame, to xlwriter'''
# inputs:
# df - pandas dataframe to save
# xl_writer - book for saving
# startrow - row from wich data frame will begins
# **kwargs - arguments of `to_excel` function of DataFrame`
df.drop(df.index).to_excel(xl_writer, startrow = startrow, **kwargs)
df.to_excel(xl_writer, startrow = startrow + 1, header = False, **kwargs)
使用示例:
y = [('K1','l'),("K1",'m'),("K2",'l'),('K2','m'),("K3",'l'),('K3','m')]
col_list = pd.MultiIndex.from_tuples(y)
A = pd.DataFrame(np.random.randint(2,5,(4,6)), columns = col_list)
xl_writer = pd.ExcelWriter("test_result/multiindex_saving.xlsx",engine='xlsxwriter')
save_double_column_df(A, xl_writer, sheet_name = 'hello')
xl_writer.close()
结果如下:
我正在尝试使用 XlsxWriter 的 to_excel 函数将 Pandas 数据帧保存到 excel 文件。
当我将数据帧打印到终端时,它会正常读取,但是当我将它保存到 excel 并打开文件时,headers 下面有一个额外的空行不应该在那里。只有在 headers 使用 MultiIndex 时才会发生这种情况,但我需要它提供的分层 headers,但我找不到解决方案。
下面是来自在线 MultiIndex 示例的代码,它产生的结果与我正在处理的项目相同。任何解决方案将不胜感激。
import numpy as np
import pandas as pd
import xlsxwriter
tuples = [('bar', 'one'), ('bar', 'two'), ('baz', 'one'), ('baz', 'two'), ('foo', 'one'), ('foo', 'two'), ('qux', 'one'), ('qux', 'two')]
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second'])
iterables = [['bar', 'baz', 'foo', 'qux'], ['one', 'two']]
pd.MultiIndex.from_product(iterables, names=['first', 'second'])
df = pd.DataFrame(np.random.randn(3, 8), index=['A', 'B', 'C'], columns=index)
print(df)
writer = pd.ExcelWriter('test.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='test1')
excel 输出创建:
这很可能是 pandas 中的错误。
有关建议的解决方案,请参阅
No easy way out of this but to delete that row by reading the xlsx in again.
还有一个link进入GitHub issue,解决这个问题。
所以我做了这个解决方法,它可能对你有帮助:
df = pd.read_excel('/home/teoretic/test.xlsx', index_col=0)
df = df.drop(np.nan) # <== dropping an empty row
rename_dct = dict.fromkeys(df.loc[:,df.columns.str.contains('^Unnamed')], '')
df = df.rename(columns=rename_dct) # <== renaming 'Unnamed' columns to blank space
writer = pd.ExcelWriter('/home/teoretic/test_new.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='test1')
writer.close()
这是一个输出文件:
非常感谢这个问题和@Teoretic 的解决方法。
但是在我的例子中,Multiindex
列的合并单元格非常有用,而那些在@Teoretic 中丢失了。我已经做了一个替代解决方法,在写入之前隐藏整行,它有效,因此我将它包含在这里以防对任何人有用。
writer = pd.ExcelWriter('test.xlsx', engine='xlsxwriter')
df.to_excel(writer, sheet_name='test1')
writer.sheets['test1'].set_row(2, None, None, {'hidden': True})
writer.save()
我找到了以下使用包 openpyxl 的解决方法,方法是读取包含空行的文件,删除该行,然后 re-writing 文件。我发现这种方法的优点是它保留了 MultiIndex 列中漂亮的合并单元格,实际上从 Excel 文件中删除了空行。通过实际删除空行,如果您的其余数据是数字,这将允许您在电子表格中开箱即用地使用 Excel 的过滤功能,而无需手动删除文件中的空行。
# Assuming df is your data frame with MultiIndex columns that you have already written to Excel
# Load the file with the empty line and select the sheet you want to edit
wb = openpyxl.load_workbook(filename = 'file_with_empty_line.xlsx')
ws = wb['sheet_name_to_edit']
# The row number to delete is 1-indexed in Excel
row_to_delete = df.columns.nlevels
ws.delete_rows(row_to_delete)
# If you want to write the name of the index into the empty cell above the index col
# after deleting the row (assuming you are writing to the first column):
ws['A'+str(row_to_delete)]=df.index.name
# Save the modified workbook to file
wb.save(filename = 'file_without_emtpy_line.xlsx')
虽然必须导入整个包来处理这个问题并不理想,但我的用例要求我不能简单地隐藏丢失的行。 @lrnzcig 的解决方案要好得多,如果你只需要隐藏空行就可以摆脱困境。
我用 ExcelWriter 删除了那个空行。我正在将 df 添加到现有的 sheet.
with pd.ExcelWriter(“PATH_TO_EXCEL”,mode=“a”,engine=“openpyxl”) as writer:
writer.book=load_workbook(“PATH_TO_EXCEL”)
df.to_excel(writer,sheet_name=“sample”,startrow=0,startcol=0)
writer.sheets[‘sample’].delete_rows(3)
我还有一个解决办法。它基于在 to_excel
函数的两次调用中保存的想法 - 第一次只保存 header,第二次保存 table 没有 header。为了实现我准备了这样的功能:
def save_double_column_df(df, xl_writer, startrow = 0, **kwargs):
'''Function to save doublecolumn DataFrame, to xlwriter'''
# inputs:
# df - pandas dataframe to save
# xl_writer - book for saving
# startrow - row from wich data frame will begins
# **kwargs - arguments of `to_excel` function of DataFrame`
df.drop(df.index).to_excel(xl_writer, startrow = startrow, **kwargs)
df.to_excel(xl_writer, startrow = startrow + 1, header = False, **kwargs)
使用示例:
y = [('K1','l'),("K1",'m'),("K2",'l'),('K2','m'),("K3",'l'),('K3','m')]
col_list = pd.MultiIndex.from_tuples(y)
A = pd.DataFrame(np.random.randint(2,5,(4,6)), columns = col_list)
xl_writer = pd.ExcelWriter("test_result/multiindex_saving.xlsx",engine='xlsxwriter')
save_double_column_df(A, xl_writer, sheet_name = 'hello')
xl_writer.close()
结果如下: