Como salvar uma nova planilha em um arquivo Excel existente, usando o Pandas?

90

Eu quero usar arquivos do Excel para armazenar dados elaborados com python. Meu problema é que não consigo adicionar planilhas a um arquivo excel existente. Aqui, sugiro um código de amostra para trabalhar a fim de resolver esse 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 salva dois DataFrames em duas planilhas, denominadas "x1" e "x2", respectivamente. Se eu criar dois novos DataFrames e tentar usar o mesmo código para adicionar duas novas planilhas, 'x3' e 'x4', os dados originais serão perdidos.

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

Quero um arquivo Excel com quatro folhas: 'x1', 'x2', 'x3', 'x4'. Eu sei que 'xlsxwriter' não é o único "motor", existe 'openpyxl'. Também vi que já existem outras pessoas que escreveram sobre esse assunto, mas ainda não consigo entender como fazer isso.

Aqui está um código retirado deste link

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

Dizem que funciona, mas é difícil descobrir como. Não entendo o que "ws.title", "ws" e "dict" são neste contexto.

Qual é a melhor maneira de salvar "x1" e "x2", fechar o arquivo, abri-lo novamente e adicionar "x3" e "x4"?

Stefano Fedele
fonte

Respostas:

121

Obrigado. Acredito que um exemplo completo pode ser bom para qualquer pessoa que tenha o mesmo 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()

Aqui eu gero um arquivo excel, do meu entendimento realmente não importa se ele é gerado através do mecanismo "xslxwriter" ou "openpyxl".

Quando quero escrever sem perder os dados originais,

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 faz o trabalho!

Stefano Fedele
fonte
alguma ideia, por que quando tento isso eu obtenho: ValueError: Nenhum escritor Excel 'Sales Leads Calculations.xlsx'?
bernando_vialli
1
sim, isso é adicionar a planilha ao excel sem apagar as planilhas pré-existentes. Obrigado!
Nikhil VJ
2
Ao salvar o arquivo do Excel, como mantenho os formatos de planilha do Excel existentes?
Vineesh TP
3
Se alguém ler isso e se perguntar como substituir uma folha existente com o mesmo nome em vez de renomear a nova: Adicione a linha writer.sheets = dict((ws.title, ws) for ws in book.worksheets) após writer.book = book
Harm te Molder
1
@Stefano Fedele você pode fazer a mesma atualização do Excel existente usando 'xlsxwriter' em vez de 'openpyxl'?
M Nikesh de
15

No exemplo que você compartilhou, você está carregando o arquivo existente booke definindo o writer.bookvalor como book. Na linha, writer.sheets = dict((ws.title, ws) for ws in book.worksheets)você está acessando cada planilha da pasta de trabalho como ws. O título da folha é então wsque você está criando um dicionário de {sheet_titles: sheet}pares de chave e valor. Este dicionário é então definido como writer.sheets. Essencialmente, essas etapas são apenas carregar os dados existentes 'Masterfile.xlsx'e preencher seu gravador com eles.

Agora, digamos que você já tenha um arquivo com x1e x2como planilhas. Você pode usar o código de exemplo para carregar o arquivo e, em seguida, fazer algo assim para adicionar x3e 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()

Isso deve fazer o que você está procurando.

Grr
fonte
alguma ideia, por que quando tento isso eu obtenho: ValueError: Nenhum escritor Excel 'Sales Leads Calculations.xlsx'?
bernando_vialli
18
isso está apagando as folhas pré-existentes.
Nikhil VJ
13

Um exemplo simples para gravar vários dados no Excel de uma vez. E também quando você deseja anexar dados a uma planilha em um arquivo Excel escrito (arquivo Excel fechado).

Quando é a primeira vez que você escreve para um excel. (Escrevendo "df1" e "df2" em "1st_sheet" e "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()    

Depois de fechar o excel, mas você deseja "anexar" dados no mesmo arquivo do Excel, mas em outra planilha, digamos "df3" ao nome da planilha "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()     

Observe que o formato do Excel não deve ser xls, você pode usar um xlsx.

Wong Tat Yau
fonte
1
Não vejo o que esta resposta acrescenta. Na verdade, o uso repetido de um gerenciador de contexto como este envolverá muito mais E / S.
Charlie Clark,
8

Eu recomendo fortemente que você trabalhe diretamente com o openpyxl, pois agora ele suporta Pandas DataFrames .

Isso permite que você se concentre no código relevante do Excel e do Pandas.

Charlie Clark
fonte
3
Seria muito útil se você pudesse adicionar um pouco mais de exemplos de "Pandas" semelhantes a este
MaxU
Eu não trabalho muito com o Pandas, então não posso fornecer tantos exemplos, mas gostaria de receber melhorias na documentação.
Charlie Clark
4

Para criar um novo arquivo

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 anexar ao arquivo, use o argumento mode='a'em 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')

O padrão é mode ='w'. Veja a documentação .

Pulkit Khandelwal
fonte
3

Pode fazer isso sem usar ExcelWriter, usando ferramentas em openpyxl Isso pode tornar a adição de fontes à nova planilha muito mais fácil usando 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
fonte
Esta é uma boa solução, mas não tenho certeza se também é uma implicação. Quer dizer que você não pode fazer isso ExcelWriterou simplesmente não precisa?
MattSom
Você pode fazer isso com o Excelwriter, mas acho mais fácil usando apenas o openpyxl.
Jis Mathew
2

Você pode ler as planilhas existentes de seus interesses, por exemplo, 'x1', 'x2', na memória e 'escrevê-las' de volta antes de adicionar mais novas planilhas (tenha em mente que as planilhas em um arquivo e as planilhas na memória são duas diferentes coisas, se você não lê-los, eles serão perdidos). Esta abordagem usa apenas 'xlsxwriter', nenhum openpyxl envolvido.

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

Se quiser preservar todas as planilhas existentes, você pode substituir o código acima entre o início e o fim por:

# 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
fonte
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
fonte
2
Não estou entendendo como isso está relacionado à questão, exceto que é sobre o Excel.
Artog de
Eu estava trabalhando para encontrar uma solução completa para ler e gravar na pasta de trabalho existente, mas não consegui encontrar a mesma. Aqui encontrei uma dica sobre como escrever em uma pasta de trabalho existente, então pensei em dar uma solução completa para o meu problema. Espero que esteja claro.
nileshk611
0

Outra maneira bastante simples de fazer isso é criar um 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)

A ideia aqui é carregar a pasta de trabalho em path_to_file se existir e, em seguida, anexar o data_frame como uma nova planilha com sheet_name . Se a pasta de trabalho não existir, ela será criada. Parece que nem openpyxl ou xlsxwriter de acréscimo, de modo que no exemplo de @Stefano acima, você realmente tem que carregar e, em seguida, reescrever a acréscimo.

MrMajestyk
fonte