จะเขียนลงไฟล์ excel ที่มีอยู่โดยไม่เขียนทับข้อมูล (โดยใช้แพนด้า) ได้อย่างไร?


121

ฉันใช้แพนด้าเขียนลงในไฟล์ 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

โปรดทราบว่ามีความสับสนในคำตอบเกี่ยวกับคำถามที่ถามกันแน่ บางคำตอบสันนิษฐานว่ายังไม่มี "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 อยู่แล้วและจะสร้างชีตใหม่
สกี

2
โซลูชันนี้ใช้งานได้ดี มันมีข้อเสียเปรียบอย่างหนึ่ง มันทำลายสูตรและการเชื่อมต่อภายในสเปรดชีต มีความคิดอย่างไรที่จะเปลี่ยนพฤติกรรมนี้?
BP_

1
หักอะไรกันแน่ .. ? คุณอาจถามคำถามนี้เป็นคำถามแยกต่างหากและติดแท็กopenpyxlและให้รายละเอียดที่เพียงพอ: คุณมีสูตรประเภทใดมีการอัปเดตข้อมูลอย่างไรมันเบรกสูตรอย่างไร ตอนนี้ฉันช่วยไม่ได้มีหลายอย่างที่ฉันไม่รู้
สกี

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)

1
โซลูชันนี้ใช้งานได้ดีสำหรับฉันส่วนอื่น ๆ ที่โพสต์ที่นี่ใช้ไม่ได้ ขอบคุณมาก! มีเพียงความคิดเห็นเดียว: เมื่อไม่มีไฟล์ฉันได้รับข้อผิดพลาด "NameError: global name 'FileNotFoundError' is not
given

1
@ cholo14 ขอบคุณที่ชี้ให้ดู! ฉันได้ทดสอบกับ Python 3.x ดังนั้นฉันจึงพลาดข้อผิดพลาดนั้น ฉันแก้ไขแล้วในคำตอบ ...
MaxU

1
สิ่งนี้ใช้ได้ผลสำหรับฉัน แต่มีวิธีรักษาการจัดรูปแบบ xlsx (จากไฟล์ xlsx ดั้งเดิม) หรือไม่
2

@ 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!

11
สิ่งนี้ไม่ได้ผลสำหรับฉัน หากมีแผ่นงาน "หลัก" อยู่แล้วแผ่นงานจะสร้างแผ่นงานใหม่ชื่อ "Main1" พร้อมกับข้อมูลใหม่เท่านั้นและปล่อยให้เนื้อหาของแผ่นงาน "หลัก" ไม่เปลี่ยนแปลง
Qululu

3
@Qululu ฉันคิดว่าอาจมีความสับสนในคำถามนี้ระหว่างสองเป้าหมายที่แตกต่างกัน วิธีนี้ช่วยให้คุณสามารถเพิ่มแผ่นงานเพิ่มเติมในสมุดงานที่มีอยู่ได้ มันเป็นเรื่องที่ไม่ได้ตั้งใจที่จะผนวกข้อมูลเพิ่มเติมให้กับแผ่นที่มีอยู่ หากมีข้อขัดแย้งในการตั้งชื่อแผ่นงานจะเปลี่ยนชื่อแผ่นงาน นี่คือคุณสมบัติไม่ใช่ข้อบกพร่อง
TC Proctor

ดังที่ @Qululu กล่าวสิ่งนี้จะสร้างแผ่นงานเพิ่มเติมโดยมีชื่อแตกต่างกัน วิธีแก้ปัญหาแรกจาก MaxU ใช้งานได้และผลลัพธ์ที่คุณจะได้รับจะเป็น df ในแผ่นงานแรกกี่ครั้งก็ได้ตามที่คุณต้องการ (นี่คือส่วนหัวคูณหลาย ๆ ครั้งเช่นกัน) เทคนิคง่ายๆหนึ่งรายการ: การวนซ้ำแต่ละครั้ง คุณต่อท้าย dataframe เข้ากับรายการ ในท้ายที่สุดคุณจะต้องเชื่อมต่อ หากทำตามโครงสร้างเดียวกันจะทำงานเป็นเสน่ห์ list_my_dfs = [df1, df2, ... ] # List of your dataframes my_dfs_together = pd.concat (list_my_df) # concat my dataframes in a single df
Susana Silva Santos

@SusanaSilvaSantos ดูสิ่งที่ TC Proctor แสดงความคิดเห็นก่อนหน้าคุณ OP ต้องการเพิ่มแผ่นงานที่ไม่มีอยู่ลงในสมุดงานที่มีอยู่ รหัสนี้ทำอย่างนั้น การผนวกข้อมูลลงในแผ่นงานที่มีอยู่ภายในสมุดงานไม่ได้เป็นส่วนหนึ่งของขอบเขต หากไม่ต้องการสิ่งนี้ก็เพียงพอแล้ว
mvbentes

16

เริ่มต้นในแพนด้า 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'เพิ่มแผ่นงานเพิ่มเติม แต่ถ้าฉันต้องการเขียนทับข้อมูลบนแผ่นงานที่มีอยู่ล่ะ?
สับสน

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 หนังสือ (ชื่อไฟล์) บนเว็บไซต์ของพวกเขาระบุว่าสร้างหนังสือ แต่มันไม่
Tinkinc

wb = xw.Book () สร้างหนังสือเปล่าเล่มใหม่เมื่อคุณผ่านเส้นทางที่คุณพยายามโหลดหนังสือที่มีอยู่
flyingmeatball

1
หมายเหตุ: xlwings โต้ตอบกับอินสแตนซ์ที่กำลังทำงานอยู่ของ Excel ดังนั้นจึงไม่ทำงานบน Linux
virtualxtc

5

มีทางออกที่ดีกว่าในแพนด้า 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
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
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
แม้ว่าสิ่งนี้อาจตอบคำถามของผู้เขียน แต่ก็ไม่มีคำอธิบายและ / หรือลิงก์ไปยังเอกสารประกอบ ข้อมูลโค้ดดิบจะไม่เป็นประโยชน์หากไม่มีวลีบางอย่างรอบตัว คุณอาจพบวิธีเขียนคำตอบที่ดีซึ่งมีประโยชน์มาก โปรดแก้ไขคำตอบของคุณ
Roy Scheffers

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'])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.