如何在不覆盖数据的情况下(使用熊猫)写入现有的excel文件?


120

我使用熊猫以以下方式写入excel文件:

import pandas

writer = pandas.ExcelWriter('Masterfile.xlsx') 

data_filtered.to_excel(writer, "Main", cols=['Diff1', 'Diff2'])

writer.save()

Masterfile.xlsx已经包含许多不同的选项卡。但是,它尚未包含“ Main”。

熊猫正确地写入了“主要”表,不幸的是,它也删除了所有其他标签。


1
你可以举一个例子还是ExcelReader?我没有在文档中找到类似的东西。
BP_

1
我认为大熊猫中没有像ExcelReader这样的东西。我使用read_excel从Excel读取数据。我认为这不会将数据保存到Excel中。
BP_

1
@nrathaus似乎没有一个ExcelReader
virtualxtc

请注意,答案中关于该问题的确切含义有些混乱。一些答案假定“主”还不存在,并且OP只是在现有的excel工作簿中添加了一个新工作表。其他人则假定“主”已经存在,并且OP希望将新数据附加到“主”的底部。
TC Proctor

Answers:


143

熊猫文档说,它对xlsx文件使用openpyxl。快速浏览一下其中的代码ExcelWriter可以提示可能会发生以下情况:

import pandas
from openpyxl import load_workbook

book = load_workbook('Masterfile.xlsx')
writer = pandas.ExcelWriter('Masterfile.xlsx', engine='openpyxl') 
writer.book = book

## ExcelWriter for some reason uses writer.sheets to access the sheet.
## If you leave it empty it will not know that sheet Main is already there
## and will create a new sheet.

writer.sheets = dict((ws.title, ws) for ws in book.worksheets)

data_filtered.to_excel(writer, "Main", cols=['Diff1', 'Diff2'])

writer.save()

2
您能解释一下writer.sheets的作用吗?
BP_

5
ExcelWriter出于某种原因使用此变量来访问工作表。如果将其保留为空,它将不知道工作表Main已经存在,并将创建一个新工作表。
2013年

2
此解决方案工作正常。但是它有一个缺点。它破坏了电子表格中的公式和连接。任何想法如何改变这种行为?
BP_

1
你到底是怎么坏的..?您可以将其作为一个单独的问题提出来,openpyxl并为其打上标签,并提供足够的详细信息:您拥有哪种公式,如何更新数据,如何使公式失效。现在我无能为力,我不知道的事情太多了。
2013年

2
可以与.xlsm文件一起使用吗?
dapaz

39

这是一个辅助函数:

def append_df_to_excel(filename, df, sheet_name='Sheet1', startrow=None,
                       truncate_sheet=False, 
                       **to_excel_kwargs):
    """
    Append a DataFrame [df] to existing Excel file [filename]
    into [sheet_name] Sheet.
    If [filename] doesn't exist, then this function will create it.

    Parameters:
      filename : File path or existing ExcelWriter
                 (Example: '/path/to/file.xlsx')
      df : dataframe to save to workbook
      sheet_name : Name of sheet which will contain DataFrame.
                   (default: 'Sheet1')
      startrow : upper left cell row to dump data frame.
                 Per default (startrow=None) calculate the last row
                 in the existing DF and write to the next row...
      truncate_sheet : truncate (remove and recreate) [sheet_name]
                       before writing DataFrame to Excel file
      to_excel_kwargs : arguments which will be passed to `DataFrame.to_excel()`
                        [can be dictionary]

    Returns: None
    """
    from openpyxl import load_workbook

    # ignore [engine] parameter if it was passed
    if 'engine' in to_excel_kwargs:
        to_excel_kwargs.pop('engine')

    writer = pd.ExcelWriter(filename, engine='openpyxl')

    # Python 2.x: define [FileNotFoundError] exception if it doesn't exist 
    try:
        FileNotFoundError
    except NameError:
        FileNotFoundError = IOError


    try:
        # try to open an existing workbook
        writer.book = load_workbook(filename)

        # get the last row in the existing Excel sheet
        # if it was not specified explicitly
        if startrow is None and sheet_name in writer.book.sheetnames:
            startrow = writer.book[sheet_name].max_row

        # truncate sheet
        if truncate_sheet and sheet_name in writer.book.sheetnames:
            # index of [sheet_name] sheet
            idx = writer.book.sheetnames.index(sheet_name)
            # remove [sheet_name]
            writer.book.remove(writer.book.worksheets[idx])
            # create an empty sheet [sheet_name] using old index
            writer.book.create_sheet(sheet_name, idx)

        # copy existing sheets
        writer.sheets = {ws.title:ws for ws in writer.book.worksheets}
    except FileNotFoundError:
        # file does not exist yet, we will create it
        pass

    if startrow is None:
        startrow = 0

    # write out the new sheet
    df.to_excel(writer, sheet_name, startrow=startrow, **to_excel_kwargs)

    # save the workbook
    writer.save()

注意:对于<0.21.0的熊猫,请替换sheet_namesheetname

用法示例:

append_df_to_excel('d:/temp/test.xlsx', df)

append_df_to_excel('d:/temp/test.xlsx', df, header=None, index=False)

append_df_to_excel('d:/temp/test.xlsx', df, sheet_name='Sheet2', index=False)

append_df_to_excel('d:/temp/test.xlsx', df, sheet_name='Sheet2', index=False, startrow=25)

1
该解决方案对我来说是完美的,此处发布的其他解决方案不起作用。非常感谢!仅有一条评论:当文件不存在时,我得到一个错误“ NameError:全局名称'FileNotFoundError'未定义”
cholo14

1
@ cholo14,谢谢您指出这一点!我已经在Python 3.x上对其进行了测试,所以我错过了该错误。我已将其修正为答案...
MaxU

1
这对我有用,但是有办法保持xlsx格式(从原始xlsx文件)吗?
酮将

@ 2one,我不完全知道-试试看或提出新的SO问题
MaxU

有没有办法写列而不是只写行?就像我想自动更新工作表一样,但不附加新行,但要感谢列!
doomdaam

21

使用openpyxlversion 2.4.0pandasversion 0.19.2,@ ski提出的过程变得更加简单:

import pandas
from openpyxl import load_workbook

with pandas.ExcelWriter('Masterfile.xlsx', engine='openpyxl') as writer:
    writer.book = load_workbook('Masterfile.xlsx')
    data_filtered.to_excel(writer, "Main", cols=['Diff1', 'Diff2'])
#That's it!

11
这对我不起作用。如果已经有一个“主”工作表,它将仅使用新数据创建一个名为“ Main1”的新工作表,而“主”工作表的内容保持不变。
Qululu

2
@Qululu我认为两个不同目标之间可能对此问题感到困惑。这使您可以将其他工作表添加到现有工作簿。它旨在附加数据添加到现有的片材。如果存在工作表命名冲突,它将重命名工作表。这是一个功能,而不是错误。
TC Proctor

正如@Qululu所说,这只会创建更多名称不同的工作表。来自MaxU的第一个解决方案起作用,并且您将获得的输出将是第一张工作表中的df,可根据需要进行多次(这是将标头也乘以多次)。一个简单的技术:每次迭代您将数据框追加到列表。最后,您只需要保持一致即可。如果它们遵循相同的结构,则将成为一种魅力。list_my_dfs = [df1,df2,...]#您的数据帧列表my_dfs_together = pd.concat(list_my_df)#将我的数据帧合并到单个df中
Susana Silva Santos

@SusanaSilvaSantos,看看您之前TC Proctor的评论。OP希望向现有工作簿中添加一个不存在的工作表。这段代码做到了。将数据追加到工作簿中的现有工作表不属于此范围。如果不需要,就足够了。
mvbentes

16

从pandas 0.24开始,您可以使用mode关键字参数简化此操作ExcelWriter

import pandas as pd

with pd.ExcelWriter('the_file.xlsx', engine='openpyxl', mode='a') as writer: 
     data_filtered.to_excel(writer) 

3
为我覆盖。
keramat

10
@keramat我认为在两个不同目标之间可能对此问题感到困惑。这使您可以将其他工作表添加到现有工作簿。它旨在附加数据添加到现有的片材。
TC Proctor

1
mode = 'a'添加更多工作表,但是如果我要覆盖现有工作表上的数据怎么办?
困惑

11

老问题了,但我猜有些人还在搜索这个-所以...

我发现此方法不错,因为所有工作表都加载到工作表名称和数据框对的字典中,该字典由熊猫使用sheetname = None选项创建。在将电子表格读取为dict格式并将其从dict写回之前,添加,删除或修改工作表很简单。对于我来说,就速度和格式而言,xlsxwriter在执行此特定任务方面比openpyxl更好。

注意:未来版本的熊猫(0.21.0+)将把“ sheetname”参数更改为“ sheet_name”。

# read a single or multi-sheet excel file
# (returns dict of sheetname(s), dataframe(s))
ws_dict = pd.read_excel(excel_file_path,
                        sheetname=None)

# all worksheets are accessible as dataframes.

# easy to change a worksheet as a dataframe:
mod_df = ws_dict['existing_worksheet']

# do work on mod_df...then reassign
ws_dict['existing_worksheet'] = mod_df

# add a dataframe to the workbook as a new worksheet with
# ws name, df as dict key, value:
ws_dict['new_worksheet'] = some_other_dataframe

# when done, write dictionary back to excel...
# xlsxwriter honors datetime and date formats
# (only included as example)...
with pd.ExcelWriter(excel_file_path,
                    engine='xlsxwriter',
                    datetime_format='yyyy-mm-dd',
                    date_format='yyyy-mm-dd') as writer:

    for ws_name, df_sheet in ws_dict.items():
        df_sheet.to_excel(writer, sheet_name=ws_name)

对于2013年问题中的示例:

ws_dict = pd.read_excel('Masterfile.xlsx',
                        sheetname=None)

ws_dict['Main'] = data_filtered[['Diff1', 'Diff2']]

with pd.ExcelWriter('Masterfile.xlsx',
                    engine='xlsxwriter') as writer:

    for ws_name, df_sheet in ws_dict.items():
        df_sheet.to_excel(writer, sheet_name=ws_name)

但是,这种工作方式并没有保留我合并的单元格,单元格颜色和单元格宽度。
virtualxtc

1
是的,使用这种方法会丢失格式的类型,因为每个工作表都将转换为熊猫数据框(没有任何excel格式),然后在新的excel工作簿(其名称与原始名称相同)中从数据框转换为工作表。文件)。看来即将出现使用openpyxl的新“附加”方法,该方法可以保留原始文件工作表格式吗? github.com/pandas-dev/pandas/pull/21251
b2002

11

我知道这是一个较旧的线程,但这是您在搜索时发现的第一项,并且如果需要将图表保留在已创建的工作簿中,则上述解决方案将不起作用。在这种情况下,xlwings是一个更好的选择-它允许您写入Excel书并保留图表/图表数据。

简单的例子:

import xlwings as xw
import pandas as pd

#create DF
months = ['2017-01','2017-02','2017-03','2017-04','2017-05','2017-06','2017-07','2017-08','2017-09','2017-10','2017-11','2017-12']
value1 = [x * 5+5 for x in range(len(months))]
df = pd.DataFrame(value1, index = months, columns = ['value1'])
df['value2'] = df['value1']+5
df['value3'] = df['value2']+5

#load workbook that has a chart in it
wb = xw.Book('C:\\data\\bookwithChart.xlsx')

ws = wb.sheets['chartData']

ws.range('A1').options(index=False).value = df

wb = xw.Book('C:\\data\\bookwithChart_updated.xlsx')

xw.apps[0].quit()

如果文件不存在,有没有办法创建文件?
Tinkinc

是的,您是否浏览过文档?docs.xlwings.org/en/stable/api.html
flyingmeatball

他们网站上的wb = xw.Book(文件名)说它创建了一本书。但事实
并非

wb = xw.Book()创建一个新的空书,当您通过它尝试加载现有书的路径时。
–flyingmeatball,

1
注意:xlwings与正在运行的Excel实例进行交互,因此不能在Linux上运行。
virtualxtc

5

在pandas 0.24中有一个更好的解决方案:

with pd.ExcelWriter(path, mode='a') as writer:
    s.to_excel(writer, sheet_name='another sheet', index=False)

之前:

在此处输入图片说明

后:

在此处输入图片说明

因此,立即升级您的熊猫:

pip install --upgrade pandas


1
只是预告将来,这不适用于该XslxWriter选件。
metinsenturk

默认情况下它不工作也做engine=openpyxl,因为它只会添加一个名为新的工作表the only worksheet1
比约恩乙

1
def append_sheet_to_master(self, master_file_path, current_file_path, sheet_name):
    try:
        master_book = load_workbook(master_file_path)
        master_writer = pandas.ExcelWriter(master_file_path, engine='openpyxl')
        master_writer.book = master_book
        master_writer.sheets = dict((ws.title, ws) for ws in master_book.worksheets)
        current_frames = pandas.ExcelFile(current_file_path).parse(pandas.ExcelFile(current_file_path).sheet_names[0],
                                                               header=None,
                                                               index_col=None)
        current_frames.to_excel(master_writer, sheet_name, index=None, header=False)

        master_writer.save()
    except Exception as e:
        raise e

这非常完美,只有主文件(添加新工作表的文件)的格式丢失了。


0
writer = pd.ExcelWriter('prueba1.xlsx'engine='openpyxl',keep_date_col=True)

“ keep_date_col”希望对您有所帮助


0
book = load_workbook(xlsFilename)
writer = pd.ExcelWriter(self.xlsFilename)
writer.book = book
writer.sheets = dict((ws.title, ws) for ws in book.worksheets)
df.to_excel(writer, sheet_name=sheetName, index=False)
writer.save()

3
尽管这可以回答作者的问题,但缺少一些解释性的单词和/或指向文档的链接。如果没有原始短语,原始代码片段不是很有帮助。您可能还会发现如何写一个好的答案很有帮助。请修改您的答案。
罗伊·谢弗斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.