Wie schreibe ich in eine vorhandene Excel-Datei, ohne Daten zu überschreiben (mit Pandas)?

120

Ich benutze Pandas, um auf folgende Weise in eine Excel-Datei zu schreiben:

import pandas

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

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

writer.save()

Masterfile.xlsx besteht bereits aus mehreren verschiedenen Registerkarten. Es enthält jedoch noch nicht "Main".

Pandas schreibt korrekt in das "Haupt" -Blatt, leider werden auch alle anderen Registerkarten gelöscht.

BP_
quelle
1
Können Sie ein Beispiel oder ExcelReader geben? Ich habe so etwas in der Dokumentation nicht gefunden.
BP_
1
Ich denke, es gibt keinen ExcelReader in Pandas. Ich benutze read_excel, um Daten aus Excel zu lesen. Ich glaube nicht, dass es Daten speichern würde, um sich zu übertreffen.
BP_
1
@nrathaus es scheint keineExcelReader
virtualxtc
Beachten Sie, dass die Antworten einige Verwirrung darüber enthalten, was genau die Frage stellt. Einige Antworten gehen davon aus, dass "Main" noch nicht vorhanden ist und das OP einfach ein neues Blatt zu einer vorhandenen Excel-Arbeitsmappe hinzufügt. Andere gehen davon aus, dass "Main" bereits vorhanden ist und dass das OP neue Daten an den unteren Rand von "Main" anhängen möchte.
TC Proctor

Antworten:

142

Pandas docs sagt, dass es openpyxl für xlsx-Dateien verwendet. Ein kurzer Blick durch den Code in ExcelWritergibt einen Hinweis darauf, dass so etwas funktionieren könnte:

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()
Ski
quelle
2
Können Sie bitte erklären, wofür writer.sheets ist?
BP_
5
Aus irgendeinem Grund verwendet ExcelWriter diese Variable, um auf das Blatt zuzugreifen. Wenn Sie es leer lassen, weiß es nicht, dass das Blatt Main bereits vorhanden ist, und erstellt ein neues Blatt.
Ski
2
Diese Lösung funktioniert gut. Es hat jedoch einen Nachteil. Es unterbricht Formeln und Verbindungen innerhalb der Tabelle. Irgendwelche Ideen, wie man dieses Verhalten ändert?
BP_
1
Was genau wirst du kaputt machen ..? Sie können dies als separate Frage stellen und mit einem Tag versehen openpyxlund genügend Details angeben: Welche Art von Formeln haben Sie, wie werden Daten aktualisiert, wie werden die Formeln gebremst? Jetzt kann ich einfach nicht anders, zu viele Dinge, die ich nicht weiß.
Ski
2
Kann es stattdessen mit XLSM-Dateien verwendet werden?
Dapaz
39

Hier ist eine Hilfsfunktion:

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

HINWEIS: für Pandas <0.21.0, ersetzen Sie sheet_namemit sheetname!

Anwendungsbeispiele:

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
quelle
1
Diese Lösung hat bei mir perfekt funktioniert, die anderen hier veröffentlichten funktionieren nicht. Vielen Dank! Nur ein Kommentar: Wenn die Datei nicht existiert, erhalte ich die Fehlermeldung "NameError: Der globale Name 'FileNotFoundError' ist nicht definiert"
cholo14
1
@ cholo14, danke, dass du darauf hingewiesen hast! Ich habe es auf Python 3.x getestet, also habe ich diesen Fehler verpasst. Ich habe es in der Antwort
behoben
1
Dies hat bei mir funktioniert, aber gibt es eine Möglichkeit, die xlsx-Formatierung (aus der ursprünglichen xlsx-Datei) beizubehalten?
2one
@ 2one, ich weiß nicht genau - probieren Sie es aus oder stellen Sie eine neue SO-Frage
MaxU
Gibt es eine Möglichkeit, in Spalten anstatt nur in Zeilen zu schreiben? Als ob ich ein Blatt automatisch aktualisieren möchte, aber keine neuen Zeilen anhängen, sondern Spalten danke!
Doomdaam
21

Mit openpyxlVersion 2.4.0und pandasVersion 0.19.2wird der von @ski entwickelte Prozess etwas einfacher:

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
quelle
11
Das funktioniert bei mir nicht. Wenn bereits ein Arbeitsblatt "Main" vorhanden ist, wird ein neues Arbeitsblatt mit dem Namen "Main1" erstellt, das nur die neuen Daten enthält, und der Inhalt des Arbeitsblatts "Main" bleibt unverändert.
Qululu
2
@ Qululu Ich denke, dass es in dieser Frage Verwirrung zwischen zwei verschiedenen Zielen geben könnte. Auf diese Weise können Sie einer vorhandenen Arbeitsmappe zusätzliche Blätter hinzufügen. Es ist nicht beabsichtigt, zusätzliche Daten an ein vorhandenes Blatt anzuhängen. Wenn ein Blattbenennungskonflikt vorliegt, wird das Blatt umbenannt. Dies ist eine Funktion, kein Fehler.
TC Proctor
Wie @Qululu sagte, werden dadurch nur mehr Blätter mit unterschiedlichen Namen erstellt. Die erste Lösung von MaxU funktioniert und die Ausgabe, die Sie erhalten, ist die df im ersten Blatt, so oft Sie möchten (dies gilt auch, wenn die Überschriften so oft multipliziert werden). Eine einfache Technik: jede Iteration Sie hängen den Datenrahmen an eine Liste an. Am Ende müssen Sie sich nur noch konzentrieren. Wenn sie der gleichen Struktur folgen, wirkt dies als Zauber. list_my_dfs = [df1, df2, ...] # Liste Ihrer Datenrahmen my_dfs_together = pd.concat (list_my_df) # Konzentrieren Sie meine Datenrahmen in einem einzigen df
Susana Silva Santos
@SusanaSilvaSantos, schauen Sie sich an, was TC Proctor kurz vor Ihnen kommentiert hat. Das OP wollte einer vorhandenen Arbeitsmappe ein nicht vorhandenes Arbeitsblatt hinzufügen. Dieser Code macht das. Das Anhängen von Daten an ein vorhandenes Blatt in der Arbeitsmappe war nicht Teil des Geltungsbereichs. Wenn dies nicht benötigt wird, reicht dies aus.
mvbentes
16

Ab Pandas 0.24 können Sie dies mit dem modeSchlüsselwortargument vereinfachen ExcelWriter:

import pandas as pd

with pd.ExcelWriter('the_file.xlsx', engine='openpyxl', mode='a') as writer: 
     data_filtered.to_excel(writer) 
Will Ayd
quelle
3
überschreibt für mich.
Keramat
10
@keramat Ich denke, dass es in dieser Frage Verwirrung zwischen zwei verschiedenen Zielen geben könnte. Auf diese Weise können Sie einer vorhandenen Arbeitsmappe zusätzliche Blätter hinzufügen. Es ist nicht beabsichtigt, zusätzliche Daten an ein vorhandenes Blatt anzuhängen.
TC Proctor
mode = 'a'Fügt weitere Blätter hinzu, aber was ist, wenn ich Daten auf den vorhandenen Blättern überschreiben möchte?
Verwirrt
11

Alte Frage, aber ich vermute, einige Leute suchen immer noch danach - also ...

Ich finde diese Methode schön, weil alle Arbeitsblätter in ein Wörterbuch mit Blattnamen- und Datenrahmenpaaren geladen werden, das von Pandas mit der Option Blattname = Keine erstellt wurde. Es ist einfach, Arbeitsblätter zwischen dem Lesen der Tabelle im Diktatformat und dem Zurückschreiben aus dem Diktat hinzuzufügen, zu löschen oder zu ändern. Für mich funktioniert der xlsxwriter in Bezug auf Geschwindigkeit und Format besser als openpyxl für diese spezielle Aufgabe.

Hinweis: Zukünftige Versionen von Pandas (0.21.0+) ändern den Parameter "Blattname" in "Blattname".

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

Für das Beispiel in der Frage 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
quelle
Diese Art funktionierte jedoch, meine zusammengeführten Zellen, Zellfarben und Zellbreiten wurden nicht beibehalten.
virtualxtc
1
Ja, bei dieser Methode geht diese Art der Formatierung verloren, da jedes Arbeitsblatt in einen Pandas-Datenrahmen (ohne diese Excel-Formatierung) konvertiert und dann in einer neuen Excel-Arbeitsmappe (die denselben Namen wie das Original hat) von Datenrahmen in Arbeitsblätter konvertiert wird Datei). Es scheint, dass eine neue "Anhängen" -Methode mit openpyxl in Kürze verfügbar sein wird, bei der die ursprüngliche Formatierung des Arbeitsblatts der Datei beibehalten wird. github.com/pandas-dev/pandas/pull/21251
b2002
11

Ich weiß, dass dies ein älterer Thread ist, aber dies ist das erste Element, das Sie bei der Suche finden, und die oben genannten Lösungen funktionieren nicht, wenn Sie Diagramme in einer bereits erstellten Arbeitsmappe beibehalten müssen. In diesem Fall ist xlwings eine bessere Option - Sie können in das Excel-Buch schreiben und die Diagramme / Diagrammdaten behalten.

einfaches Beispiel:

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()
fliegender Fleischbällchen
quelle
Gibt es eine Möglichkeit, eine Datei zu erstellen, wenn sie nicht zuerst vorhanden ist?
Tinkinc
Ja, haben Sie die Dokumente untersucht? docs.xlwings.org/en/stable/api.html
FlyingMeatball
wb = xw.Book (Dateiname) auf ihrer Website sagt, dass es ein Buch erstellt. aber es tut nicht
Tinkinc
wb = xw.Book () erstellt ein neues leeres Buch. Wenn Sie einen Pfad übergeben, versuchen Sie, ein vorhandenes Buch zu laden.
FlyingMeatball
1
Hinweis: xlwings interagiert mit einer laufenden Instanz von Excel und kann daher nicht unter Linux ausgeführt werden.
virtualxtc
5

Es gibt eine bessere Lösung in Pandas 0.24:

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

Vor:

Geben Sie hier die Bildbeschreibung ein

nach dem:

Geben Sie hier die Bildbeschreibung ein

Aktualisieren Sie jetzt Ihre Pandas:

pip install --upgrade pandas
schwarzes Schaf
quelle
1
Dies ist ein Duplikat dieser früheren Antwort
TC Proctor
1
Nur ein Heads-up für die Zukunft, dies funktioniert mit der XslxWriterOption nicht.
Metinsenturk
Es funktioniert auch standardmäßig nicht, engine=openpyxlda nur ein neues Arbeitsblatt mit dem Namenthe 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

Dies funktioniert einwandfrei, nur dass die Formatierung der Master-Datei (Datei, zu der wir ein neues Blatt hinzufügen) verloren geht.

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

Die Hoffnung "keep_date_col" hilft Ihnen

Edward
quelle
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()
Pedro Machado
quelle
3
Dies könnte zwar die Frage der Autoren beantworten, es fehlen jedoch einige erklärende Wörter und / oder Links zur Dokumentation. Rohcode-Schnipsel sind ohne einige Ausdrücke nicht sehr hilfreich. Möglicherweise ist es auch sehr hilfreich , eine gute Antwort zu schreiben . Bitte bearbeiten Sie Ihre Antwort.
Roy Scheffers