Skip to content

Pandas DataFrame para CSV: Guia Completo de to_csv()

Updated on

Voce limpou os dados, transformou cada coluna e executou sua analise. Agora precisa compartilhar os resultados -- e o arquivo CSV que voce exporta abre com caracteres ilegiveis no Excel, uma coluna de indice indesejada, ou um arquivo de 4 GB que trava o notebook do seu colega. Exportar um DataFrame do Pandas para CSV parece simples ate que codificacao, separadores, compressao e desempenho com arquivos grandes transformem uma unica linha de codigo em uma sessao de depuracao.

Esses problemas sao comuns porque to_csv() tem mais de 20 parametros, e os valores padrao nem sempre correspondem ao que os consumidores downstream esperam. Uma codificacao errada quebra texto nao-ASCII. Um index=False ausente adiciona uma coluna misteriosa. Sem compressao, um conjunto de dados razoavel se torna um anexo superdimensionado.

O metodo DataFrame.to_csv() lida com todos esses casos quando voce sabe quais parametros definir. Este guia percorre cada cenario pratico -- desde exportacao basica ate escrita em blocos de DataFrames com milhoes de linhas -- para que voce possa exportar dados corretamente na primeira tentativa.

📚

Uso Basico

A chamada mais simples escreve um DataFrame em um arquivo CSV no diretorio de trabalho atual:

import pandas as pd
 
df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Charlie'],
    'age': [28, 35, 42],
    'salary': [72000, 88000, 95000]
})
 
df.to_csv('employees.csv')

Isso cria employees.csv com o seguinte conteudo:

,name,age,salary
0,Alice,28,72000
1,Bob,35,88000
2,Charlie,42,95000

Note a primeira coluna -- esse e o indice do DataFrame. Na maioria das vezes voce nao o quer. Corrija com index=False:

df.to_csv('employees.csv', index=False)

Saida:

name,age,salary
Alice,28,72000
Bob,35,88000
Charlie,42,95000

Assinatura Completa do Metodo

Aqui esta a assinatura completa de to_csv() com os parametros mais usados:

DataFrame.to_csv(
    path_or_buf=None,   # caminho do arquivo ou buffer
    sep=',',            # delimitador
    na_rep='',          # string para valores ausentes
    float_format=None,  # formato para floats
    columns=None,       # subconjunto de colunas
    header=True,        # escrever nomes de colunas
    index=True,         # escrever indice de linhas
    index_label=None,   # rotulo da coluna de indice
    mode='w',           # modo de escrita ('w', 'a', 'x')
    encoding=None,      # codificacao (padrao utf-8)
    compression='infer',# tipo de compressao
    quoting=None,       # constante csv.QUOTE_*
    lineterminator=None,# caractere de fim de linha
    chunksize=None,     # linhas por bloco
    date_format=None,   # formato para datas
    errors='strict',    # tratamento de erros de codificacao
)

Parametros Principais Explicados

sep -- Delimitadores Personalizados

Nem todo sistema le virgulas. Use sep para mudar o delimitador:

import pandas as pd
 
df = pd.DataFrame({
    'product': ['Widget A', 'Widget B'],
    'price': [19.99, 29.99]
})
 
# Separado por tabulacao
df.to_csv('products.tsv', sep='\t', index=False)
 
# Separado por ponto e virgula (comum em configuracoes europeias)
df.to_csv('products_eu.csv', sep=';', index=False)
 
# Separado por pipe
df.to_csv('products.txt', sep='|', index=False)

columns -- Exportar um Subconjunto

Escreva apenas colunas especificas em vez do DataFrame inteiro:

import pandas as pd
 
df = pd.DataFrame({
    'id': [1, 2, 3],
    'name': ['Alice', 'Bob', 'Charlie'],
    'email': ['a@x.com', 'b@x.com', 'c@x.com'],
    'internal_score': [0.87, 0.92, 0.78]
})
 
# Exportar apenas as colunas que o cliente precisa
df.to_csv('export.csv', columns=['id', 'name', 'email'], index=False)

header -- Controlar Nomes de Colunas

import pandas as pd
 
df = pd.DataFrame({
    'name': ['Alice', 'Bob'],
    'score': [85, 92]
})
 
# Sem linha de cabecalho
df.to_csv('no_header.csv', header=False, index=False)
 
# Nomes de cabecalho personalizados
df.to_csv('custom_header.csv', header=['Nome Completo', 'Nota do Teste'], index=False)

na_rep -- Representar Valores Ausentes

Por padrao, valores NaN se tornam strings vazias. Use na_rep para torna-los explicitos:

import pandas as pd
import numpy as np
 
df = pd.DataFrame({
    'sensor': ['A', 'B', 'C'],
    'reading': [23.5, np.nan, 18.2]
})
 
# Padrao: string vazia para NaN
df.to_csv('readings_default.csv', index=False)
# sensor,reading
# A,23.5
# B,
# C,18.2
 
# Marcador explicito de valor ausente
df.to_csv('readings_marked.csv', na_rep='NULL', index=False)
# sensor,reading
# A,23.5
# B,NULL
# C,18.2

float_format -- Controlar Precisao Decimal

import pandas as pd
 
df = pd.DataFrame({
    'item': ['Widget', 'Gadget'],
    'price': [19.999999, 42.123456]
})
 
# Duas casas decimais
df.to_csv('prices.csv', float_format='%.2f', index=False)
# item,price
# Widget,20.00
# Gadget,42.12

date_format -- Formatar Colunas de Data/Hora

import pandas as pd
 
df = pd.DataFrame({
    'event': ['Launch', 'Review'],
    'date': pd.to_datetime(['2026-03-15 14:30:00', '2026-04-01 09:00:00'])
})
 
# Apenas data ISO (sem hora)
df.to_csv('events.csv', date_format='%Y-%m-%d', index=False)
# event,date
# Launch,2026-03-15
# Review,2026-04-01

Tratamento de Codificacao e Caracteres Especiais

Codificacao e a causa numero um de arquivos CSV com caracteres ilegiveis. A codificacao padrao em to_csv() e utf-8, que funciona para a maioria dos sistemas. Mas o Excel no Windows espera um BOM (Byte Order Mark) para exibir corretamente caracteres nao-ASCII.

UTF-8 (Padrao)

import pandas as pd
 
df = pd.DataFrame({
    'city': ['Zurique', 'Munique', 'Toquio'],
    'greeting': ['Ola', 'Servus', 'Konnichiwa']
})
 
# UTF-8 padrao
df.to_csv('cities.csv', index=False, encoding='utf-8')

UTF-8 com BOM para Excel

Se seu CSV contem caracteres acentuados, texto CJK ou simbolos especiais e precisa abrir corretamente no Microsoft Excel:

import pandas as pd
 
df = pd.DataFrame({
    'city': ['Zurique', 'Munique', 'Sao Paulo', 'Pequim'],
    'population': [434000, 1472000, 12330000, 21540000]
})
 
# utf-8-sig adiciona um BOM que o Excel reconhece
df.to_csv('cities_excel.csv', index=False, encoding='utf-8-sig')

Outras Codificacoes

import pandas as pd
 
df = pd.DataFrame({'col': ['data']})
 
# Latin-1 para sistemas europeus ocidentais legados
df.to_csv('legacy.csv', index=False, encoding='latin-1')
 
# Shift-JIS para sistemas japoneses legados
df.to_csv('japanese.csv', index=False, encoding='shift_jis')
CodificacaoQuando UsarCompativel com Excel?
utf-8Padrao para maioria dos sistemas, APIs, bancos de dadosParcial (sem BOM)
utf-8-sigExcel no Windows com texto nao-ASCIISim
latin-1 / iso-8859-1Sistemas europeus ocidentais legadosSim
shift_jisSistemas japoneses legadosSim
cp1252Windows europeu ocidentalSim

DataFrames Grandes: Compressao e Chunking

Compressao

Compressao reduz o tamanho do arquivo em 60-90% sem perda de dados. Pandas suporta multiplos formatos:

import pandas as pd
import numpy as np
 
# Criar um DataFrame grande
df = pd.DataFrame({
    'id': range(1_000_000),
    'value': np.random.randn(1_000_000),
    'category': np.random.choice(['A', 'B', 'C', 'D'], 1_000_000)
})
 
# Compressao gzip (mais comum)
df.to_csv('large_data.csv.gz', index=False, compression='gzip')
 
# Compressao zip
df.to_csv('large_data.zip', index=False, compression='zip')
 
# Compressao bz2 (menor mas mais lento)
df.to_csv('large_data.csv.bz2', index=False, compression='bz2')
 
# Zstandard (rapido, boa razao -- requer pacote zstandard)
df.to_csv('large_data.csv.zst', index=False, compression='zstd')
CompressaoExtensaoVelocidadeReducao de TamanhoLeitura
Nenhuma.csvEscrita mais rapida0%pd.read_csv('f.csv')
gzip.csv.gzModerada70-85%pd.read_csv('f.csv.gz')
zip.zipModerada70-85%pd.read_csv('f.zip')
bz2.csv.bz2Lenta75-90%pd.read_csv('f.csv.bz2')
zstd.csv.zstRapida70-85%pd.read_csv('f.csv.zst')

Pandas infere automaticamente o formato de compressao pela extensao do arquivo, entao compression='infer' (o padrao) geralmente funciona.

Chunksize -- Escrever em Lotes

Para DataFrames muito grandes que sobrecarregam a memoria, escreva em blocos:

import pandas as pd
import numpy as np
 
df = pd.DataFrame({
    'id': range(5_000_000),
    'value': np.random.randn(5_000_000)
})
 
# Escrever 500.000 linhas por vez
df.to_csv('huge_data.csv', index=False, chunksize=500_000)

O parametro chunksize nao reduz o tamanho final do arquivo -- ele controla quantas linhas sao gravadas no disco de uma vez. Isso pode ajudar a reduzir o pico de uso de memoria durante a operacao de escrita.

Escrever em String ou Buffer

Voce nem sempre escreve em um arquivo. As vezes precisa do CSV como string para uma chamada de API, insercao em banco de dados ou processamento em memoria:

import pandas as pd
 
df = pd.DataFrame({
    'name': ['Alice', 'Bob'],
    'score': [85, 92]
})
 
# Obter CSV como string
csv_string = df.to_csv(index=False)
print(csv_string)
# name,score
# Alice,85
# Bob,92

Escrever em StringIO ou BytesIO

import pandas as pd
from io import StringIO, BytesIO
 
df = pd.DataFrame({
    'x': [1, 2, 3],
    'y': [4, 5, 6]
})
 
# Buffer StringIO
buffer = StringIO()
df.to_csv(buffer, index=False)
csv_text = buffer.getvalue()
 
# Buffer BytesIO (util para respostas HTTP, uploads S3)
byte_buffer = BytesIO()
df.to_csv(byte_buffer, index=False, encoding='utf-8')
csv_bytes = byte_buffer.getvalue()

Esse padrao e comum ao fazer upload de dados CSV para armazenamento em nuvem (S3, GCS) sem criar um arquivo local.

Adicionar a um CSV Existente

Para adicionar linhas a um arquivo existente sem sobrescreve-lo, use mode='a' e header=False:

import pandas as pd
 
# Primeiro lote -- escrever com cabecalho
df1 = pd.DataFrame({'name': ['Alice'], 'score': [85]})
df1.to_csv('results.csv', index=False)
 
# Segundo lote -- adicionar sem duplicar o cabecalho
df2 = pd.DataFrame({'name': ['Bob', 'Charlie'], 'score': [92, 78]})
df2.to_csv('results.csv', mode='a', header=False, index=False)

O arquivo resultante tem uma linha de cabecalho seguida de tres linhas de dados. Omitir header=False inseriria uma segunda linha de cabecalho no meio dos dados.

Aspas e Escape

Campos contendo o delimitador, quebras de linha ou aspas precisam de tratamento adequado. Pandas lida com isso automaticamente, mas voce pode controlar o comportamento:

import pandas as pd
import csv
 
df = pd.DataFrame({
    'name': ['O\'Brien', 'Smith, Jr.', 'Alice "Ace" Wong'],
    'notes': ['Contem apostrofo', 'Contem virgula', 'Contem aspas']
})
 
# Padrao: aspas apenas quando necessario (QUOTE_MINIMAL)
df.to_csv('minimal.csv', index=False)
 
# Aspas em todos os campos
df.to_csv('all_quoted.csv', index=False, quoting=csv.QUOTE_ALL)
 
# Aspas apenas em campos nao numericos
df.to_csv('nonnumeric.csv', index=False, quoting=csv.QUOTE_NONNUMERIC)

Comparacao de Formatos de Exportacao: to_csv() vs to_excel() vs to_parquet()

Escolher o formato de exportacao correto depende de quem consome o arquivo e do seu tamanho:

Caracteristicato_csv()to_excel()to_parquet()
Formato do arquivoTexto puroBinario (xlsx)Binario (colunar)
Legivel por humanosSimVia Excel/SheetsNao
Tamanho do arquivo (1M linhas)~50-100 MB~30-60 MB~5-15 MB
Velocidade de escritaRapidaLentaRapida
Velocidade de leituraModeradaLentaMuito rapida
Preservacao de tiposNao (tudo strings)ParcialCompleta
Requer biblioteca extraNaoopenpyxlpyarrow / fastparquet
Suporte a compressaogzip, zip, bz2, zstdIntegradoIntegrado (snappy, gzip)
Melhor paraInteroperabilidade, APIs, compartilhamento rapidoUsuarios de negocio, usuarios ExcelPipelines de analise, big data

Regra geral: Use CSV para compartilhar dados com usuarios nao tecnicos ou sistemas externos. Use Parquet para pipelines internos onde velocidade e fidelidade de tipos importam. Use Excel quando o destinatario precisa de formatacao ou multiplas planilhas.

Armadilhas Comuns e Como Evita-las

1. Coluna de Indice Indesejada

A reclamacao mais frequente. Sempre passe index=False a menos que seu indice contenha dados significativos:

# Errado -- adiciona coluna misteriosa "Unnamed: 0" ao ler
df.to_csv('data.csv')
 
# Correto
df.to_csv('data.csv', index=False)

2. Colunas Sem Nome na Releitura

Se voce exportou com indice e depois leu o arquivo, voce obtem uma coluna Unnamed: 0:

import pandas as pd
 
# Lendo CSV que foi exportado com indice
df = pd.read_csv('data.csv', index_col=0)  # dizer ao read_csv qual coluna e o indice

3. Perda de Precisao de Data/Hora

Sem date_format, colunas de data/hora sao exportadas como timestamps completos incluindo microssegundos. Controle isso explicitamente:

import pandas as pd
 
df = pd.DataFrame({
    'ts': pd.to_datetime(['2026-01-15 08:30:00.123456'])
})
 
df.to_csv('ts.csv', index=False, date_format='%Y-%m-%d %H:%M:%S')

4. Problemas de Arredondamento de Floats

Numeros de ponto flutuante podem produzir digitos finais inesperados:

import pandas as pd
 
df = pd.DataFrame({'val': [0.1 + 0.2]})
df.to_csv('float.csv', index=False)
# val
# 0.30000000000000004
 
df.to_csv('float_clean.csv', index=False, float_format='%.2f')
# val
# 0.30

5. Tipos Mistos em uma Coluna

Se uma coluna tem tipos mistos (inteiros e strings), to_csv() converte tudo em strings. Verifique seus tipos de dados antes de exportar:

import pandas as pd
 
df = pd.DataFrame({'id': [1, 2, 'three']})
print(df.dtypes)
# id    object  <-- tipo misto
 
# Limpar antes de exportar
df['id'] = pd.to_numeric(df['id'], errors='coerce')
df.to_csv('clean.csv', index=False)

Visualize Seus Dados Antes de Exportar com PyGWalker

Antes de exportar um DataFrame para CSV, e util verificar se os dados estao corretos. PyGWalker (opens in a new tab) transforma qualquer DataFrame do Pandas em uma interface visual interativa dentro do Jupyter Notebook -- arraste e solte colunas para criar graficos sem escrever codigo de plotagem:

import pandas as pd
import pygwalker as pyg
 
df = pd.read_csv('raw_data.csv')
 
# Explorar visualmente antes de exportar
walker = pyg.walk(df)
 
# Quando satisfeito, exportar
df.to_csv('verified_export.csv', index=False, encoding='utf-8-sig')

Esse fluxo de trabalho detecta problemas como valores nulos inesperados, outliers ou tipos de dados incorretos antes que eles cheguem ao consumidor do CSV.

FAQ

Como exporto um DataFrame do Pandas para CSV sem o indice?

Passe index=False para to_csv(): df.to_csv('file.csv', index=False). Isso evita que o indice de linhas seja escrito como a primeira coluna. Ao ler o arquivo de volta, voce nao vera uma coluna extra Unnamed: 0.

Como lido com caracteres especiais e codificacao ao exportar para CSV?

Use encoding='utf-8-sig' se o CSV precisa abrir corretamente no Microsoft Excel com caracteres nao-ASCII (letras acentuadas, texto CJK). Para sistemas padrao e APIs, o encoding='utf-8' padrao funciona. Para sistemas legados, use a codificacao especifica que eles requerem (latin-1, shift_jis, etc.).

Como comprimo um arquivo CSV grande ao exportar do Pandas?

Adicione uma extensao de compressao ao nome do arquivo e o Pandas cuida do resto: df.to_csv('data.csv.gz', index=False) cria um arquivo comprimido com gzip. Voce tambem pode definir compression='gzip', 'zip', 'bz2' ou 'zstd' explicitamente. Arquivos comprimidos sao tipicamente 70-90% menores e podem ser lidos diretamente com pd.read_csv().

Posso adicionar dados a um arquivo CSV existente em vez de sobrescreve-lo?

Sim. Use mode='a' e header=False: df.to_csv('file.csv', mode='a', header=False, index=False). mode='a' abre o arquivo para adicao, e header=False evita escrever um cabecalho duplicado no meio do arquivo.

Qual e a diferenca entre to_csv() e to_parquet() no Pandas?

to_csv() produz um arquivo de texto legivel por humanos mas perde informacao de tipos (tudo se torna strings). to_parquet() cria um arquivo binario compacto que preserva tipos de dados (inteiros, floats, datas), e lido 5-10x mais rapido e e 5-10x menor. Use CSV para compartilhar com usuarios nao tecnicos ou sistemas externos. Use Parquet para pipelines de dados internos onde desempenho e fidelidade de tipos importam.

Conclusao

DataFrame.to_csv() e a forma padrao de exportar dados do Pandas para arquivos CSV. Para exportacoes limpas, sempre passe index=False. Use encoding='utf-8-sig' quando compatibilidade com Excel for importante. Comprima arquivos grandes com gzip ou zstd para reduzir o tamanho em 70-90%. Controle a precisao decimal com float_format, trate valores ausentes com na_rep e adicione a arquivos existentes com mode='a'. Para pipelines de dados onde preservacao de tipos e velocidade importam, considere to_parquet() em vez disso. Antes de exportar, verifique seus dados visualmente com ferramentas como PyGWalker para detectar problemas cedo.

📚