Как записать в существующий файл Excel без перезаписи данных (с помощью pandas)?

121

Я использую pandas для записи в файл excel следующим образом:

import pandas

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

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

writer.save()

Masterfile.xlsx уже состоит из нескольких разных вкладок. Однако в нем еще нет «Main».

Pandas правильно пишет на "Основном" листе, но, к сожалению, удаляет и все остальные вкладки.

BP_
источник
1
можешь привести пример или ExcelReader? Ничего подобного в документации не нашел.
BP_
1
Думаю, в пандах нет такого понятия, как ExcelReader. Я использую read_excel для чтения данных из excel. Я не думаю, что это поможет сохранить данные, чтобы преуспеть.
BP_
1
@nrathaus, похоже, нетExcelReader
virtualxtc
Обратите внимание, что в ответах есть некоторая путаница в том, что именно задает вопрос. В некоторых ответах предполагается, что «Main» еще не существует, а OP просто добавляет новый лист в существующую книгу Excel. Другие предполагают, что «Main» уже существует, и что OP хочет добавить новые данные в конец «Main».
TC Proctor

Ответы:

143

В документации Pandas говорится, что он использует openpyxl для файлов xlsx. Быстрый просмотр кода 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 уже существует, и создаст новый лист.
Ski
2
Это решение отлично работает. Однако у него есть один недостаток. Он нарушает формулы и связи в электронной таблице. Есть идеи, как изменить это поведение?
BP_
1
Что именно у вас сломалось ..? Вы можете задать это как отдельный вопрос, пометив его openpyxlи предоставить достаточно подробностей: какие у вас формулы, как обновляются данные, как это мешает формулам. Теперь я просто не могу помочь, слишком многого не знаю.
Ski
2
можно ли его использовать с файлами .xlsm?
dapaz
40

Вот вспомогательная функция:

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()

ПРИМЕЧАНИЕ: для Pandas <0,21,0 заменить sheet_nameнаsheetname !

Примеры использования:

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)
MaxU
источник
1
Это решение отлично сработало для меня, другие, опубликованные здесь, не работают. Большое спасибо! Только один комментарий: когда файл не существует, я получаю сообщение об ошибке «NameError: глобальное имя FileNotFoundError не определено»
cholo14
1
@ cholo14, спасибо, что указали на это! Я тестировал его на Python 3.x, поэтому пропустил эту ошибку. Я исправил это в ответе ...
MaxU
1
Это сработало для меня, но есть ли способ сохранить форматирование xlsx (из исходного файла xlsx)?
2one,
@ 2one, я точно не знаю - попробуйте или задайте новый вопрос SO
MaxU
есть ли способ писать в столбцы, а не только в строки? Как будто я хочу автоматически обновлять лист, но не добавлять новые строки, а столбцы, спасибо!
doomdaam
21

С openpyxlверсией 2.4.0и pandasверсией 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!
mvbentes
источник
11
У меня это не работает. Если «Основной» рабочий лист уже существует, он создаст новый с именем «Main1» только с новыми данными и оставит содержимое «Основного» рабочего листа без изменений.
Qululu
3
@Qululu Я думаю, что в этом вопросе может возникнуть путаница между двумя разными целями. Это позволяет добавлять дополнительные листы в существующую книгу. Он не предназначен для добавления дополнительных данных к существующему листу. Если возникает конфликт именования листов, он переименовывает лист. Это особенность, а не ошибка.
TC Proctor
Как сказал @Qululu, это только создает больше листов с разными именами. Первое решение от MaxU работает, и на выходе вы получите df на первом листе столько раз, сколько вам нужно (то есть с заголовками, умноженными на столько же раз). Одна простая техника: каждая итерация вы добавляете фрейм данных в список. В конце концов, вам нужно только concat. Если они будут следовать одной и той же структуре, они будут работать как оберег. 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) 
Уилл Айд
источник
4
перезаписывает для меня.
keramat
10
@keramat Я думаю, что в этом вопросе может возникнуть путаница между двумя разными целями. Это позволяет добавлять дополнительные листы в существующую книгу. Он не предназначен для добавления дополнительных данных к существующему листу.
TC Proctor
1
mode = 'a'добавляет больше листов, но что, если я хочу перезаписать данные на существующих листах?
Confaken
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()
flyingmeatball
источник
Есть ли способ сначала создать файл, если он не существует?
Tinkinc
Да, вы изучали документы? docs.xlwings.org/en/stable/api.html
flyingmeatball
wb = xw.Book (имя файла) на их веб-сайте говорит, что создает книгу. но это не так
Tinkinc
wb = xw.Book () создает новую пустую книгу, когда вы передаете ей путь, по которому вы пытаетесь загрузить существующую книгу.
flyingmeatball
1
Примечание. Xlwings взаимодействует с запущенным экземпляром Excel и поэтому не работает в Linux.
virtualxtc
10

Старый вопрос, но я предполагаю, что некоторые люди все еще ищут это - так что ...

Мне этот метод нравится, потому что все листы загружаются в словарь пар имени листа и фрейма данных, созданный пандами с параметром Sheetname = None. Легко добавлять, удалять или изменять рабочие листы между чтением таблицы в формате dict и записью ее обратно из dict. Для меня xlsxwriter работает лучше, чем openpyxl для этой конкретной задачи с точки зрения скорости и формата.

Примечание: будущие версии pandas (0.21.0+) изменят параметр «имя листа» на «имя_ листа».

# 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)
b2002
источник
Этот вид работал, однако мои объединенные ячейки, цвета ячеек и ширина ячеек не сохранились.
virtualxtc
1
Да, с помощью этого метода этот тип форматирования будет потерян, потому что каждый рабочий лист преобразуется в фрейм данных pandas (без такого форматирования Excel), а затем преобразуется из фреймов данных в листы в новой книге Excel (которая имеет то же имя, что и исходная файл). Похоже, что скоро появится новый метод «добавления» с использованием openpyxl, который может сохранить исходное форматирование рабочего листа файла? github.com/pandas-dev/pandas/pull/21251
b2002
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
Это дубликат этого более раннего ответа
TC Proctor
1
Просто предупреждение на будущее, это не работает с XslxWriterопцией.
metinsenturk
он также по умолчанию не работает, engine=openpyxlпоскольку он просто добавит новый рабочий лист под названиемthe only worksheet1
Björn B
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
Хотя это может ответить на вопрос авторов, в нем отсутствуют некоторые поясняющие слова и / или ссылки на документацию. Фрагменты необработанного кода не очень полезны без некоторых фраз. Вы также можете найти очень полезным, как написать хороший ответ . Пожалуйста, отредактируйте свой ответ.
Рой Шефферс
0

Метод:

  • Можно создать файл, если его нет
  • Добавить в существующий Excel в соответствии с именем листа
import pandas as pd
from openpyxl import load_workbook

def write_to_excel(df, file):
    try:
        book = load_workbook(file)
        writer = pd.ExcelWriter(file, engine='openpyxl') 
        writer.book = book
        writer.sheets = dict((ws.title, ws) for ws in book.worksheets)
        df.to_excel(writer, **kwds)
        writer.save()
    except FileNotFoundError as e:
        df.to_excel(file, **kwds)

Использование:

df_a = pd.DataFrame(range(10), columns=["a"])
df_b = pd.DataFrame(range(10, 20), columns=["b"])
write_to_excel(df_a, "test.xlsx", sheet_name="Sheet a", columns=['a'], index=False)
write_to_excel(df_b, "test.xlsx", sheet_name="Sheet b", columns=['b'])
BPPuneeth Pai
источник