¿Cómo guardar una nueva hoja en un archivo de Excel existente, usando Pandas?

86

Quiero usar archivos de Excel para almacenar datos elaborados con Python. Mi problema es que no puedo agregar hojas a un archivo de Excel existente. Aquí sugiero un código de muestra para trabajar con el fin de llegar a este problema

import pandas as pd
import numpy as np

path = r"C:\Users\fedel\Desktop\excelData\PhD_data.xlsx"

x1 = np.random.randn(100, 2)
df1 = pd.DataFrame(x1)

x2 = np.random.randn(100, 2)
df2 = pd.DataFrame(x2)

writer = pd.ExcelWriter(path, engine = 'xlsxwriter')
df1.to_excel(writer, sheet_name = 'x1')
df2.to_excel(writer, sheet_name = 'x2')
writer.save()
writer.close()

Este código guarda dos DataFrames en dos hojas, denominadas "x1" y "x2" respectivamente. Si creo dos nuevos DataFrames e intento usar el mismo código para agregar dos hojas nuevas, 'x3' y 'x4', los datos originales se pierden.

import pandas as pd
import numpy as np

path = r"C:\Users\fedel\Desktop\excelData\PhD_data.xlsx"

x3 = np.random.randn(100, 2)
df3 = pd.DataFrame(x3)

x4 = np.random.randn(100, 2)
df4 = pd.DataFrame(x4)

writer = pd.ExcelWriter(path, engine = 'xlsxwriter')
df3.to_excel(writer, sheet_name = 'x3')
df4.to_excel(writer, sheet_name = 'x4')
writer.save()
writer.close()

Quiero un archivo de Excel con cuatro hojas: 'x1', 'x2', 'x3', 'x4'. Sé que 'xlsxwriter' no es el único "motor", existe 'openpyxl'. También vi que ya hay otras personas que han escrito sobre este tema, pero todavía no puedo entender cómo hacerlo.

Aquí un código tomado de este enlace

import pandas
from openpyxl import load_workbook

book = load_workbook('Masterfile.xlsx')
writer = pandas.ExcelWriter('Masterfile.xlsx', engine='openpyxl') 
writer.book = book
writer.sheets = dict((ws.title, ws) for ws in book.worksheets)

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

writer.save()

Dicen que funciona, pero es difícil saber cómo. No entiendo qué son "ws.title", "ws" y "dict" en este contexto.

¿Cuál es la mejor manera de guardar "x1" y "x2", luego cerrar el archivo, abrirlo nuevamente y agregar "x3" y "x4"?

Stefano Fedele
fuente

Respuestas:

116

Gracias. Creo que un ejemplo completo podría ser bueno para cualquier otra persona que tenga el mismo problema:

import pandas as pd
import numpy as np

path = r"C:\Users\fedel\Desktop\excelData\PhD_data.xlsx"

x1 = np.random.randn(100, 2)
df1 = pd.DataFrame(x1)

x2 = np.random.randn(100, 2)
df2 = pd.DataFrame(x2)

writer = pd.ExcelWriter(path, engine = 'xlsxwriter')
df1.to_excel(writer, sheet_name = 'x1')
df2.to_excel(writer, sheet_name = 'x2')
writer.save()
writer.close()

Aquí genero un archivo de Excel, según tengo entendido, realmente no importa si se genera a través del motor "xslxwriter" o "openpyxl".

Cuando quiero escribir sin perder los datos originales, entonces

import pandas as pd
import numpy as np
from openpyxl import load_workbook

path = r"C:\Users\fedel\Desktop\excelData\PhD_data.xlsx"

book = load_workbook(path)
writer = pd.ExcelWriter(path, engine = 'openpyxl')
writer.book = book

x3 = np.random.randn(100, 2)
df3 = pd.DataFrame(x3)

x4 = np.random.randn(100, 2)
df4 = pd.DataFrame(x4)

df3.to_excel(writer, sheet_name = 'x3')
df4.to_excel(writer, sheet_name = 'x4')
writer.save()
writer.close()

este código hace el trabajo!

Stefano Fedele
fuente
alguna idea, ¿por qué cuando intento esto obtengo: ValueError: No hay escritor de Excel 'Sales Leads Calculations.xlsx'?
bernando_vialli
1
sí, esto es agregar la hoja a Excel sin borrar las hojas preexistentes. ¡Gracias!
Nikhil VJ
2
Cuando guardo el archivo de Excel, ¿cómo conservo los formatos de hoja de Excel existentes?
Vineesh TP
3
Si alguien lee esto y se pregunta cómo sobrescribir una hoja existente con el mismo nombre en lugar de cambiar el nombre de la nueva: agregue la línea writer.sheets = dict((ws.title, ws) for ws in book.worksheets) después de writer.book = book
Harm te Molder
1
@Stefano Fedele ¿puedes hacer la misma actualización de Excel existente usando 'xlsxwriter' en lugar de 'openpyxl'?
M Nikesh
15

En el ejemplo que compartió, está cargando el archivo existente booky estableciendo el writer.bookvalor en book. En la línea writer.sheets = dict((ws.title, ws) for ws in book.worksheets), accede a cada hoja del libro como ws. El título de la hoja es entonces wspara que esté creando un diccionario de {sheet_titles: sheet}pares clave y valor. A continuación, este diccionario se establece en writer.sheets. Básicamente, estos pasos son solo cargar los datos existentes 'Masterfile.xlsx'y completar su escritor con ellos.

Ahora digamos que ya tiene un archivo con x1y x2como hojas. Puede usar el código de ejemplo para cargar el archivo y luego podría hacer algo como esto para agregar x3y x4.

path = r"C:\Users\fedel\Desktop\excelData\PhD_data.xlsx"
writer = pd.ExcelWriter(path, engine='openpyxl')
df3.to_excel(writer, 'x3', index=False)
df4.to_excel(writer, 'x4', index=False)
writer.save()

Eso debería hacer lo que estás buscando.

Grr
fuente
alguna idea, ¿por qué cuando intento esto obtengo: ValueError: No hay escritor de Excel 'Sales Leads Calculations.xlsx'?
bernando_vialli
18
esto es borrar las hojas preexistentes.
Nikhil VJ
13

Un ejemplo simple para escribir varios datos para sobresalir a la vez. Y también cuando desee agregar datos a una hoja en un archivo de Excel escrito (archivo de Excel cerrado).

Cuando es la primera vez que escribe en Excel. (Escribiendo "df1" y "df2" en "1st_sheet" y "2nd_sheet")

import pandas as pd 
from openpyxl import load_workbook

df1 = pd.DataFrame([[1],[1]], columns=['a'])
df2 = pd.DataFrame([[2],[2]], columns=['b'])
df3 = pd.DataFrame([[3],[3]], columns=['c'])

excel_dir = "my/excel/dir"

with pd.ExcelWriter(excel_dir, engine='xlsxwriter') as writer:    
    df1.to_excel(writer, '1st_sheet')   
    df2.to_excel(writer, '2nd_sheet')   
    writer.save()    

Después de cerrar su Excel, pero desea "agregar" datos en el mismo archivo de Excel pero en otra hoja, digamos "df3" al nombre de la hoja "3rd_sheet".

book = load_workbook(excel_dir)
with pd.ExcelWriter(excel_dir, engine='openpyxl') as writer:
    writer.book = book
    writer.sheets = dict((ws.title, ws) for ws in book.worksheets)    

    ## Your dataframe to append. 
    df3.to_excel(writer, '3rd_sheet')  

    writer.save()     

Tenga en cuenta que el formato de Excel no debe ser xls, puede usar xlsx one.

Wong Tat Yau
fuente
1
No veo lo que agrega esta respuesta. De hecho, el uso repetido de un administrador de contexto como este implicará muchas más E / S.
Charlie Clark
8

Le recomiendo encarecidamente que trabaje directamente con openpyxl, ya que ahora es compatible con Pandas DataFrames .

Esto le permite concentrarse en el código relevante de Excel y Pandas.

Charlie Clark
fuente
3
Sería realmente útil si pudieras agregar un poco más de ejemplos de "Pandas" similares a este
MaxU
Yo mismo no trabajo mucho con Pandas, así que no puedo proporcionar tantos ejemplos, pero agradecería mejoras en la documentación.
Charlie Clark
4

Para crear un nuevo archivo

x1 = np.random.randn(100, 2)
df1 = pd.DataFrame(x1)
with pd.ExcelWriter('sample.xlsx') as writer:  
    df1.to_excel(writer, sheet_name='x1')

Para agregar al archivo, use el argumento mode='a'en pd.ExcelWriter.

x2 = np.random.randn(100, 2)
df2 = pd.DataFrame(x2)
with pd.ExcelWriter('sample.xlsx', engine='openpyxl', mode='a') as writer:  
    df2.to_excel(writer, sheet_name='x2')

El valor predeterminado es mode ='w'. Ver documentación .

Pulkit Khandelwal
fuente
3

Puede hacerlo sin usar ExcelWriter, usando herramientas en openpyxl Esto puede hacer que agregar fuentes a la nueva hoja sea mucho más fácil de usar openpyxl.styles

import pandas as pd
from openpyxl import load_workbook
from openpyxl.utils.dataframe import dataframe_to_rows

#Location of original excel sheet
fileLocation =r'C:\workspace\data.xlsx'

#Location of new file which can be the same as original file
writeLocation=r'C:\workspace\dataNew.xlsx'

data = {'Name':['Tom','Paul','Jeremy'],'Age':[32,43,34],'Salary':[20000,34000,32000]}

#The dataframe you want to add
df = pd.DataFrame(data)

#Load existing sheet as it is
book = load_workbook(fileLocation)
#create a new sheet
sheet = book.create_sheet("Sheet Name")

#Load dataframe into new sheet
for row in dataframe_to_rows(df, index=False, header=True):
    sheet.append(row)

#Save the modified excel at desired location    
book.save(writeLocation)
Jis Mathew
fuente
Esta es una buena solución, sin embargo, no estoy seguro de si también es una implicación. ¿Quiere decir que no puede hacerlo con ExcelWritero simplemente no es necesario?
MattSom
Puede hacerlo con Excelwriter, pero lo encuentro más fácil con solo usar openpyxl.
Jis Mathew
2

Puede leer las hojas existentes de sus intereses, por ejemplo, 'x1', 'x2', en la memoria y 'escribirlas' antes de agregar más hojas nuevas (tenga en cuenta que las hojas en un archivo y las hojas en la memoria son dos diferentes cosas, si no las lees, se perderán). Este enfoque utiliza solo 'xlsxwriter', sin openpyxl involucrado.

import pandas as pd
import numpy as np

path = r"C:\Users\fedel\Desktop\excelData\PhD_data.xlsx"

# begin <== read selected sheets and write them back
df1 = pd.read_excel(path, sheet_name='x1', index_col=0) # or sheet_name=0
df2 = pd.read_excel(path, sheet_name='x2', index_col=0) # or sheet_name=1
writer = pd.ExcelWriter(path, engine='xlsxwriter')
df1.to_excel(writer, sheet_name='x1')
df2.to_excel(writer, sheet_name='x2')
# end ==>

# now create more new sheets
x3 = np.random.randn(100, 2)
df3 = pd.DataFrame(x3)

x4 = np.random.randn(100, 2)
df4 = pd.DataFrame(x4)

df3.to_excel(writer, sheet_name='x3')
df4.to_excel(writer, sheet_name='x4')
writer.save()
writer.close()

Si desea conservar todas las hojas existentes, puede reemplazar el código anterior entre el comienzo y el final con:

# read all existing sheets and write them back
writer = pd.ExcelWriter(path, engine='xlsxwriter')
xlsx = pd.ExcelFile(path)
for sheet in xlsx.sheet_names:
    df = xlsx.parse(sheet_name=sheet, index_col=0)
    df.to_excel(writer, sheet_name=sheet)
Jonathan L
fuente
1
#This program is to read from excel workbook to fetch only the URL domain names and write to the existing excel workbook in a different sheet..
#Developer - Nilesh K
import pandas as pd
from openpyxl import load_workbook #for writting to the existing workbook

df = pd.read_excel("urlsearch_test.xlsx")

#You can use the below for the relative path.
# r"C:\Users\xyz\Desktop\Python\

l = [] #To make a list in for loop

#begin
#loop starts here for fetching http from a string and iterate thru the entire sheet. You can have your own logic here.
for index, row in df.iterrows():
    try: 
        str = (row['TEXT']) #string to read and iterate
        y = (index)
        str_pos = str.index('http') #fetched the index position for http
        str_pos1 = str.index('/', str.index('/')+2) #fetched the second 3rd position of / starting from http
        str_op = str[str_pos:str_pos1] #Substring the domain name
        l.append(str_op) #append the list with domain names

    #Error handling to skip the error rows and continue.
    except ValueError:
            print('Error!')
print(l)
l = list(dict.fromkeys(l)) #Keep distinct values, you can comment this line to get all the values
df1 = pd.DataFrame(l,columns=['URL']) #Create dataframe using the list
#end

#Write using openpyxl so it can be written to same workbook
book = load_workbook('urlsearch_test.xlsx')
writer = pd.ExcelWriter('urlsearch_test.xlsx',engine = 'openpyxl')
writer.book = book
df1.to_excel(writer,sheet_name = 'Sheet3')
writer.save()
writer.close()

#The below can be used to write to a different workbook without using openpyxl
#df1.to_excel(r"C:\Users\xyz\Desktop\Python\urlsearch1_test.xlsx",index='false',sheet_name='sheet1')
nileshk611
fuente
1
No sigo cómo esto se relaciona con la pregunta, excepto que se trata de Excel.
Artog
Estaba trabajando para encontrar una solución completa para leer y escribir en un libro de trabajo existente, pero no pude encontrar lo mismo. Aquí encontré una pista sobre cómo escribir en un libro de trabajo existente, así que pensé en dar una solución completa para mi problema. Espero que esté claro.
nileshk611
0

Otra forma bastante sencilla de hacerlo es crear un método como este:

def _write_frame_to_new_sheet(path_to_file=None, sheet_name='sheet', data_frame=None):
    book = None
    try:
        book = load_workbook(path_to_file)
    except Exception:
        logging.debug('Creating new workbook at %s', path_to_file)
    with pd.ExcelWriter(path_to_file, engine='openpyxl') as writer:
        if book is not None:
            writer.book = book
        data_frame.to_excel(writer, sheet_name, index=False)

La idea aquí es cargar el libro de trabajo en path_to_file si existe y luego agregar el data_frame como una nueva hoja con sheet_name . Si el libro de trabajo no existe, se crea. Parece que ni openpyxl o xlsxwriter anexados, así como en el ejemplo anterior por @Stefano, que realmente tienen que carga y vuelva a grabar para anexar.

MrMajestyk
fuente