Bagaimana cara menulis ke file excel yang sudah ada tanpa menimpa data (menggunakan panda)?

120

Saya menggunakan panda untuk menulis ke file excel dengan cara berikut:

import pandas

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

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

writer.save()

Masterfile.xlsx sudah terdiri dari beberapa tab yang berbeda. Namun, itu belum mengandung "Utama".

Pandas menulis dengan benar ke sheet "Utama", sayangnya itu juga menghapus semua tab lainnya.

BP_
sumber
1
dapatkah Anda memberikan contoh atau ExcelReader? Saya belum menemukan yang seperti ini di dokumentasi.
BP_
1
Saya rasa tidak ada hal seperti ExcelReader di panda. Saya menggunakan read_excel untuk membaca data dari excel. Saya tidak berpikir itu akan menghemat data untuk unggul.
BP_
1
@nrathaus sepertinya tidak adaExcelReader
virtualxtc
Perhatikan bahwa ada beberapa kebingungan dalam jawaban tentang apa sebenarnya pertanyaan itu. Beberapa jawaban berasumsi bahwa "Utama" belum ada, dan OP hanya menambahkan lembar baru ke buku kerja excel yang sudah ada. Yang lain menganggap "Utama" sudah ada, dan OP ingin menambahkan data baru ke bagian bawah "Utama".
TC Proctor

Jawaban:

143

Dokumen Pandas mengatakan itu menggunakan openpyxl untuk file xlsx. Melihat sekilas kode di dalam ExcelWritermemberikan petunjuk bahwa sesuatu seperti ini mungkin berhasil:

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()
Main ski
sumber
2
Bisakah Anda menjelaskan untuk apa writer.sheets itu?
BP_
5
ExcelWriter karena alasan tertentu menggunakan variabel ini untuk mengakses sheet. Jika Anda membiarkannya kosong, ia tidak akan tahu bahwa sheet Utama sudah ada di sana dan akan membuat sheet baru.
Ski
2
Solusi ini berfungsi dengan baik. Ini memiliki satu kelemahan. Ini merusak rumus dan koneksi di dalam spreadsheet. Ada ide bagaimana mengubah perilaku ini?
BP_
1
Apa sebenarnya yang membuat Anda hancur ..? Anda dapat menanyakan ini sebagai pertanyaan terpisah dan memberi tag openpyxlserta memberikan detail yang cukup: jenis rumus yang Anda miliki, bagaimana data diperbarui, bagaimana cara mengerem rumus. Sekarang saya tidak bisa membantu, terlalu banyak hal yang saya tidak tahu.
Ski
2
dapatkah itu digunakan dengan file .xlsm?
dapaz
39

Berikut adalah fungsi pembantu:

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

CATATAN: untuk Pandas <0.21.0, ganti sheet_namedengan sheetname!

Contoh penggunaan:

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
sumber
1
Solusi ini berfungsi sempurna untuk saya, solusi lain yang diposting di sini tidak berfungsi. Terima kasih banyak! Hanya satu komentar: ketika file tidak ada, saya mendapatkan pesan kesalahan "NameError: nama global 'FileNotFoundError' tidak ditentukan"
cholo14
1
@ cholo14, terima kasih telah menunjukkan hal ini! Saya sudah mengujinya di Python 3.x, jadi saya melewatkan bug itu. Saya sudah memperbaikinya di jawaban ...
MaxU
1
Ini berhasil untuk saya, tetapi apakah ada cara untuk mempertahankan pemformatan xlsx (dari file xlsx asli)?
2satu
@ 2one, saya tidak tahu persis - cobalah atau ajukan pertanyaan SO baru
MaxU
adakah cara untuk menulis ke kolom dan bukan hanya baris? Seperti saya ingin memperbarui lembar secara otomatis, tetapi tidak menambahkan baris baru, tetapi kolom terima kasih!
doomdaam
21

Dengan openpyxlversi 2.4.0dan pandasversinya 0.19.2, proses yang dibuat oleh @ski menjadi sedikit lebih sederhana:

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
sumber
11
Ini tidak berhasil untuk saya. Jika sudah ada lembar kerja "Utama", ini akan membuat yang baru bernama "Main1" dengan data baru saja dan membiarkan isi lembar kerja "Utama" tidak berubah.
Qululu
3
@ Qululu Saya pikir mungkin ada kebingungan tentang pertanyaan ini antara dua tujuan yang berbeda. Ini memungkinkan Anda untuk menambahkan lembar tambahan ke buku kerja yang sudah ada. Ini tidak dimaksudkan untuk menambahkan data tambahan ke lembar yang sudah ada. Jika ada konflik penamaan sheet, itu mengganti nama sheet. Ini adalah fitur, bukan bug.
TC Proctor
Seperti yang dikatakan @Qululu, ini hanya membuat lebih banyak sheet, dengan nama berbeda. Solusi pertama, dari MaxU works, dan output yang akan Anda dapatkan, adalah df di lembar pertama, sebanyak yang Anda inginkan (ini, dengan header dikalikan berkali-kali juga.) Satu teknik sederhana: setiap iterasi Anda menambahkan kerangka data ke daftar. Pada akhirnya Anda hanya perlu melakukan concat. Jika mereka mengikuti struktur yang sama akan berfungsi sebagai pesona. list_my_dfs = [df1, df2, ...] # Daftar dataframe Anda my_dfs_together = pd.concat (list_my_df) # concat dataframes saya dalam satu df
Susana Silva Santos
@SusanaSilvaSantos, lihat apa yang dikomentari TC Proctor sebelum Anda. OP ingin menambahkan lembar kerja yang tidak ada ke buku kerja yang sudah ada. Kode ini melakukan itu. Menambahkan data ke lembar yang sudah ada di dalam buku kerja bukanlah bagian dari cakupan. Jika itu tidak diperlukan, ini sudah cukup.
mvbentes
16

Mulai dari pandas 0.24 Anda dapat menyederhanakannya dengan modeargumen kata kunci ExcelWriter:

import pandas as pd

with pd.ExcelWriter('the_file.xlsx', engine='openpyxl', mode='a') as writer: 
     data_filtered.to_excel(writer) 
Will Ayd
sumber
3
menimpa untuk saya.
keramat
10
@keramat Saya pikir mungkin ada kebingungan tentang pertanyaan ini antara dua tujuan yang berbeda. Ini memungkinkan Anda untuk menambahkan lembar tambahan ke buku kerja yang sudah ada. Ini tidak dimaksudkan untuk menambahkan data tambahan ke lembar yang sudah ada.
TC Proctor
1
mode = 'a'menambahkan lebih banyak lembar, tetapi bagaimana jika saya ingin menimpa data pada lembar yang sudah ada?
Bingung
11

Pertanyaan lama, tapi saya rasa beberapa orang masih mencari ini - jadi ...

Saya menemukan metode ini bagus karena semua lembar kerja dimuat ke dalam kamus nama lembar dan pasangan kerangka data, dibuat oleh panda dengan opsi nama lembar = Tidak ada. Sangat mudah untuk menambahkan, menghapus, atau memodifikasi lembar kerja antara membaca spreadsheet ke dalam format dict dan menulisnya kembali dari dict. Bagi saya xlsxwriter bekerja lebih baik daripada openpyxl untuk tugas khusus ini dalam hal kecepatan dan format.

Catatan: versi panda yang akan datang (0.21.0+) akan mengubah parameter "sheetname" menjadi "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)

Untuk contoh pada pertanyaan 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
sumber
Jenis ini berhasil, namun, sel gabungan, warna sel, dan lebar sel saya tidak dipertahankan.
virtualxtc
1
Ya, dengan metode ini jenis pemformatan tersebut akan hilang karena setiap lembar kerja diubah menjadi bingkai data pandas (dengan tidak ada pemformatan excel itu), lalu dikonversi dari kerangka data ke lembar kerja di dalam buku kerja excel baru (yang memiliki nama yang sama dengan aslinya mengajukan). Tampaknya metode "tambahkan" baru menggunakan openpyxl mungkin akan datang yang mungkin mempertahankan format lembar kerja file asli? github.com/pandas-dev/pandas/pull/21251
b2002
11

Saya tahu ini adalah utas yang lebih lama, tetapi ini adalah item pertama yang Anda temukan saat mencari, dan solusi di atas tidak berfungsi jika Anda perlu menyimpan bagan di buku kerja yang sudah Anda buat. Dalam hal ini, xlwings adalah pilihan yang lebih baik - ini memungkinkan Anda untuk menulis ke buku excel dan menyimpan data grafik / grafik.

contoh sederhana:

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
sumber
Apakah ada cara untuk membuat file jika tidak ada terlebih dahulu?
Tinkinc
Ya, apakah Anda menjelajahi dokumen? docs.xlwings.org/en/stable/api.html
flyingmeatball
wb = xw. Buku (nama file) di situs web mereka mengatakan itu membuat buku. tetapi tidak
Tinkinc
wb = xw.Book () membuat buku kosong baru, saat Anda memberikannya jalur Anda mencoba memuat buku yang sudah ada.
flyingmeatball
1
Catatan: xlwings berinteraksi dengan contoh Excel yang sedang berjalan dan oleh karena itu tidak berjalan di Linux.
virtualxtc
5

Ada solusi yang lebih baik di panda 0.24:

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

sebelum:

masukkan deskripsi gambar di sini

setelah:

masukkan deskripsi gambar di sini

jadi tingkatkan panda Anda sekarang:

pip install --upgrade pandas
kambing hitam
sumber
1
Ini adalah duplikat dari jawaban sebelumnya
TC Proctor
1
Hanya peringatan untuk masa depan, ini tidak berfungsi dengan XslxWriteropsi.
metinsenturk
itu juga secara default tidak berfungsi engine=openpyxlkarena hanya akan menambahkan lembar kerja baru yang disebutthe 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

Ini berfungsi dengan baik, satu-satunya hal adalah pemformatan file master (file yang kami tambahkan lembar baru) hilang.

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

The "keep_date_col" harap membantu Anda

Edward
sumber
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
sumber
3
Meskipun ini mungkin menjawab pertanyaan penulis, ini kekurangan beberapa kata yang menjelaskan dan / atau tautan ke dokumentasi. Potongan kode mentah tidak terlalu membantu tanpa beberapa frase di sekitarnya. Anda juga mungkin menemukan cara menulis jawaban yang bagus sangat membantu. Harap edit jawaban Anda.
Roy Scheffers
0

Metode:

  • Dapat membuat file jika tidak ada
  • Tambahkan ke excel yang ada sesuai nama sheet
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)

Pemakaian:

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
sumber