Come scrivere su un file excel esistente senza sovrascrivere i dati (utilizzando i panda)?


120

Uso i panda per scrivere su file Excel nel modo seguente:

import pandas

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

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

writer.save()

Masterfile.xlsx è già costituito da un numero di schede diverse. Tuttavia, non contiene ancora "Main".

Pandas scrive correttamente sul foglio "Principale", purtroppo cancella anche tutte le altre schede.


1
puoi fare un esempio o ExcelReader? Non ho trovato niente di simile nella documentazione.
BP_

1
Penso che non ci sia qualcosa come ExcelReader nei panda. Uso read_excel per leggere i dati da Excel. Non credo che salverebbe i dati per eccellere.
BP_

1
@nrathaus non sembra esserci unExcelReader
virtualxtc

Nota che c'è una certa confusione nelle risposte su ciò che sta chiedendo esattamente la domanda. Alcune risposte presumono che "Principale" non esista ancora e l'OP sta semplicemente aggiungendo un nuovo foglio a una cartella di lavoro Excel esistente. Altri presumono che "Main" esista già e che l'OP voglia aggiungere nuovi dati in fondo a "Main".
TC Proctor

Risposte:


143

Pandas docs dice che usa openpyxl per i file xlsx. Una rapida occhiata al codice ExcelWriterfornisce un indizio che qualcosa del genere potrebbe funzionare:

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
Puoi spiegare per favore a cosa serve writer.sheets?
BP_

5
ExcelWriter per qualche motivo utilizza questa variabile per accedere al foglio. Se lo lasci vuoto non saprà che il foglio principale è già presente e creerà un nuovo foglio.
Sci

2
Questa soluzione funziona bene. Tuttavia ha uno svantaggio. Rompe formule e connessioni all'interno del foglio di calcolo. Qualche idea su come cambiare questo comportamento?
BP_

1
Cosa ti rompi esattamente ..? Potresti porre questa domanda come una domanda separata e contrassegnarla con openpyxle fornire dettagli sufficienti: che tipo di formule hai, come vengono aggiornati i dati, come interrompono le formule. Ora non posso proprio aiutare, troppe cose non so.
Sci

2
può essere utilizzato con file .xlsm invece?
dapaz

39

Ecco una funzione di supporto:

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

NOTA: per Panda <0.21.0, sostituire sheet_namecon sheetname!

Esempi di utilizzo:

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
Questa soluzione ha funzionato perfettamente per me, le altre pubblicate qui non funzionano. Molte grazie! Solo un commento: quando il file non esiste, ottengo un errore "NameError: il nome globale 'FileNotFoundError' non è definito"
cholo14

1
@ cholo14, grazie per averlo fatto notare! L'ho testato su Python 3.x, quindi ho perso quel bug. L'ho risolto nella risposta ...
MaxU

1
Questo ha funzionato per me, ma c'è un modo per mantenere la formattazione xlsx (dal file xlsx originale)?
2un

@ 2one, non lo so esattamente - provalo o fai una nuova domanda SO
MaxU

c'è un modo per scrivere su colonne invece che solo su righe? Come se volessi aggiornare un foglio automaticamente, ma non aggiungendo nuove righe, ma colonne grazie!
doomdaam

21

Con openpyxlversion 2.4.0e pandasversion 0.19.2, il processo inventato da @ski diventa un po 'più semplice:

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
Questo non funziona per me. Se è già presente un foglio di lavoro "Principale", ne creerà uno nuovo denominato "Principale1" solo con i nuovi dati e lascerà invariato il contenuto del foglio di lavoro "Principale".
Qululu

3
@Qululu Penso che potrebbe esserci confusione su questa domanda tra due obiettivi diversi. Ciò consente di aggiungere fogli aggiuntivi a una cartella di lavoro esistente. Non ha lo scopo di aggiungere dati aggiuntivi a un foglio esistente. Se c'è un conflitto di denominazione del foglio, rinomina il foglio. Questa è una caratteristica, non un bug.
TC Proctor

Come ha detto @Qululu, questo crea solo più fogli, con nomi diversi. La prima soluzione, da MaxU funziona, e l'output che otterrai, sarà il df nel primo foglio, tutte le volte che vuoi (questo è, con anche le intestazioni moltiplicate tante volte.) Una semplice tecnica: ogni iterazione aggiungi il dataframe a un elenco. Alla fine devi solo concatenare. Se seguono la stessa struttura funzionerà come un fascino. list_my_dfs = [df1, df2, ...] # List of your dataframes my_dfs_together = pd.concat (list_my_df) # concatena i miei dataframe in un singolo df
Susana Silva Santos

@SusanaSilvaSantos, dai un'occhiata a cosa ha commentato TC Proctor poco prima di te. L'OP voleva aggiungere un foglio di lavoro inesistente a una cartella di lavoro esistente. Questo codice lo fa. L'aggiunta di dati a un foglio esistente all'interno della cartella di lavoro non faceva parte dell'ambito. Se non è necessario, sarà sufficiente.
mvbentes

16

A partire da panda 0.24 puoi semplificarlo con l' modeargomento parola chiave di ExcelWriter:

import pandas as pd

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

3
sovrascrive per me.
Keramat

10
@keramat Penso che potrebbe esserci confusione su questa domanda tra due obiettivi diversi. Ciò consente di aggiungere fogli aggiuntivi a una cartella di lavoro esistente. Non ha lo scopo di aggiungere dati aggiuntivi a un foglio esistente.
TC Proctor

1
mode = 'a'aggiunge più fogli, ma cosa succede se voglio sovrascrivere i dati sui fogli esistenti?
Confuso il

11

Vecchia domanda, ma immagino che alcune persone lo cerchino ancora, quindi ...

Trovo questo metodo carino perché tutti i fogli di lavoro vengono caricati in un dizionario di coppie di nomi di fogli e dataframe, creato dai panda con l'opzione sheetname = None. È semplice aggiungere, eliminare o modificare fogli di lavoro tra la lettura del foglio di calcolo nel formato dict e la riscrittura dal dict. Per me xlsxwriter funziona meglio di openpyxl per questa particolare attività in termini di velocità e formato.

Nota: le future versioni di panda (0.21.0+) cambieranno il parametro "sheetname" in "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)

Per l'esempio nella domanda del 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)

Questo tipo di funzionamento, tuttavia, le mie celle unite, i colori delle celle e le larghezze delle celle non sono state preservate.
virtualxtc

1
Sì, con questo metodo quel tipo di formattazione andrà perso perché ogni foglio di lavoro viene convertito in un dataframe panda (senza nessuna formattazione Excel), quindi convertito da dataframe a fogli di lavoro all'interno di una nuova cartella di lavoro Excel (che ha lo stesso nome dell'originale file). Sembra che sia in arrivo un nuovo metodo "append" utilizzando openpyxl che potrebbe preservare la formattazione del foglio di lavoro del file originale? github.com/pandas-dev/pandas/pull/21251
b2002

11

So che questo è un thread più vecchio, ma questo è il primo elemento che trovi durante la ricerca e le soluzioni di cui sopra non funzionano se devi conservare i grafici in una cartella di lavoro che hai già creato. In tal caso, xlwings è un'opzione migliore: ti consente di scrivere sul libro Excel e conserva i grafici / dati del grafico.

semplice esempio:

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

C'è un modo per creare il file se non esiste prima?
Tinkinc

Sì, hai esplorato i documenti? docs.xlwings.org/en/stable/api.html
flyingmeatball

wb = xw.Book (nome file) sul loro sito web dice che crea un libro. ma non è così
Tinkinc

wb = xw.Book () crea un nuovo libro vuoto, quando gli passi un percorso stai cercando di caricare un libro esistente.
flyingmeatball

1
Nota: xlwings interagisce con un'istanza in esecuzione di Excel e quindi non funziona su Linux.
virtualxtc

5

C'è una soluzione migliore in panda 0.24:

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

prima:

inserisci qui la descrizione dell'immagine

dopo:

inserisci qui la descrizione dell'immagine

quindi aggiorna i tuoi panda ora:

pip install --upgrade pandas

1
Questo è un duplicato di questa risposta precedente
TC Proctor

1
Solo un avvertimento per il futuro, questo non funziona con l' XslxWriteropzione.
metinsenturk

Inoltre per impostazione predefinita non funziona engine=openpyxlin quanto aggiungerà solo un nuovo foglio di lavoro chiamatothe 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

Funziona perfettamente, l'unica cosa è che la formattazione del file master (file a cui aggiungiamo un nuovo foglio) viene persa.


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

La speranza "keep_date_col" ti aiuta


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
Sebbene questo possa rispondere alla domanda degli autori, mancano alcune parole esplicative e / o collegamenti alla documentazione. Gli snippet di codice non elaborati non sono molto utili senza alcune frasi intorno ad essi. Potresti anche trovare molto utile come scrivere una buona risposta . Modifica la tua risposta.
Roy Scheffers

0

Metodo:

  • Può creare file se non presente
  • Aggiungi a excel esistente secondo il nome del foglio
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)

Uso:

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'])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.