Pandas DataFrame a CSV: Guia Completa de to_csv()
Updated on
Limpio los datos, transformo cada columna y ejecuto el analisis. Ahora necesita compartir los resultados -- y el archivo CSV que exporta se abre con caracteres ilegibles en Excel, una columna de indice no deseada, o un archivo de 4 GB que colapsa el portatil de su colega. Exportar un DataFrame de Pandas a CSV suena simple hasta que la codificacion, los separadores, la compresion y el rendimiento con archivos grandes convierten una linea de codigo en una sesion de depuracion.
Estos problemas son comunes porque to_csv() tiene mas de 20 parametros, y los valores predeterminados no siempre coinciden con lo que los consumidores posteriores esperan. Una codificacion incorrecta rompe el texto no ASCII. Un index=False faltante agrega una columna misteriosa. Sin compresion, un conjunto de datos razonable se convierte en un archivo adjunto de gran tamano.
El metodo DataFrame.to_csv() maneja todos estos casos una vez que sabe que parametros configurar. Esta guia recorre cada escenario practico -- desde la exportacion basica hasta la escritura en bloques de DataFrames con millones de filas -- para que pueda exportar datos correctamente al primer intento.
Uso Basico
La llamada mas simple escribe un DataFrame en un archivo CSV en el directorio de trabajo actual:
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob', 'Charlie'],
'age': [28, 35, 42],
'salary': [72000, 88000, 95000]
})
df.to_csv('employees.csv')Esto crea employees.csv con el siguiente contenido:
,name,age,salary
0,Alice,28,72000
1,Bob,35,88000
2,Charlie,42,95000Note la primera columna -- ese es el indice del DataFrame. La mayoria de las veces no lo necesita. Corrija esto con index=False:
df.to_csv('employees.csv', index=False)Salida:
name,age,salary
Alice,28,72000
Bob,35,88000
Charlie,42,95000Firma Completa del Metodo
Aqui esta la firma completa de to_csv() con los parametros que usara con mas frecuencia:
DataFrame.to_csv(
path_or_buf=None, # ruta de archivo o buffer
sep=',', # delimitador
na_rep='', # cadena para valores faltantes
float_format=None, # formato para flotantes
columns=None, # subconjunto de columnas a escribir
header=True, # escribir nombres de columnas
index=True, # escribir indice de filas
index_label=None, # etiqueta de columna para el indice
mode='w', # modo de escritura ('w', 'a', 'x')
encoding=None, # codificacion del archivo (por defecto utf-8)
compression='infer',# tipo de compresion
quoting=None, # constante csv.QUOTE_*
lineterminator=None,# caracter de fin de linea
chunksize=None, # filas por bloque
date_format=None, # formato para fecha/hora
errors='strict', # manejo de errores de codificacion
)Parametros Clave Explicados
sep -- Delimitadores Personalizados
No todos los sistemas leen comas. Use sep para cambiar el delimitador:
import pandas as pd
df = pd.DataFrame({
'product': ['Widget A', 'Widget B'],
'price': [19.99, 29.99]
})
# Separado por tabulaciones
df.to_csv('products.tsv', sep='\t', index=False)
# Separado por punto y coma (comun en configuraciones europeas)
df.to_csv('products_eu.csv', sep=';', index=False)
# Separado por pipe
df.to_csv('products.txt', sep='|', index=False)columns -- Exportar un Subconjunto
Escriba solo columnas especificas en lugar del DataFrame completo:
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 solo las columnas que el cliente necesita
df.to_csv('export.csv', columns=['id', 'name', 'email'], index=False)header -- Controlar Nombres de Columnas
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob'],
'score': [85, 92]
})
# Sin fila de encabezado
df.to_csv('no_header.csv', header=False, index=False)
# Nombres de encabezado personalizados
df.to_csv('custom_header.csv', header=['Nombre Completo', 'Puntuacion'], index=False)na_rep -- Representar Valores Faltantes
Por defecto, los valores NaN se convierten en cadenas vacias. Use na_rep para hacerlos explicitos:
import pandas as pd
import numpy as np
df = pd.DataFrame({
'sensor': ['A', 'B', 'C'],
'reading': [23.5, np.nan, 18.2]
})
# Por defecto: cadena vacia para NaN
df.to_csv('readings_default.csv', index=False)
# sensor,reading
# A,23.5
# B,
# C,18.2
# Marcador explicito de valor faltante
df.to_csv('readings_marked.csv', na_rep='NULL', index=False)
# sensor,reading
# A,23.5
# B,NULL
# C,18.2float_format -- Controlar Precision Decimal
import pandas as pd
df = pd.DataFrame({
'item': ['Widget', 'Gadget'],
'price': [19.999999, 42.123456]
})
# Dos decimales
df.to_csv('prices.csv', float_format='%.2f', index=False)
# item,price
# Widget,20.00
# Gadget,42.12date_format -- Formatear Columnas de Fecha/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'])
})
# Solo fecha ISO (sin hora)
df.to_csv('events.csv', date_format='%Y-%m-%d', index=False)
# event,date
# Launch,2026-03-15
# Review,2026-04-01Manejo de Codificacion y Caracteres Especiales
La codificacion es la causa numero uno de archivos CSV con caracteres ilegibles. La codificacion predeterminada en to_csv() es utf-8, que funciona para la mayoria de los sistemas. Pero Excel en Windows espera un BOM (Byte Order Mark) para mostrar correctamente los caracteres no ASCII.
UTF-8 (Predeterminado)
import pandas as pd
df = pd.DataFrame({
'city': ['Zurich', 'Munich', 'Tokyo'],
'greeting': ['Gruezi', 'Servus', 'Konnichiwa']
})
# UTF-8 estandar
df.to_csv('cities.csv', index=False, encoding='utf-8')UTF-8 con BOM para Excel
Si su CSV contiene caracteres acentuados, texto CJK o simbolos especiales y necesita abrirse correctamente en Microsoft Excel:
import pandas as pd
df = pd.DataFrame({
'city': ['Zurich', 'Munich', 'Sao Paulo', 'Beijing'],
'population': [434000, 1472000, 12330000, 21540000]
})
# utf-8-sig agrega un BOM que Excel reconoce
df.to_csv('cities_excel.csv', index=False, encoding='utf-8-sig')Otras Codificaciones
import pandas as pd
df = pd.DataFrame({'col': ['data']})
# Latin-1 para sistemas europeos occidentales heredados
df.to_csv('legacy.csv', index=False, encoding='latin-1')
# Shift-JIS para sistemas japoneses heredados
df.to_csv('japanese.csv', index=False, encoding='shift_jis')| Codificacion | Cuando Usar | Compatible con Excel? |
|---|---|---|
utf-8 | Predeterminado para la mayoria de sistemas, APIs, bases de datos | Parcial (sin BOM) |
utf-8-sig | Excel en Windows con texto no ASCII | Si |
latin-1 / iso-8859-1 | Sistemas europeos occidentales heredados | Si |
shift_jis | Sistemas japoneses heredados | Si |
cp1252 | Windows europeo occidental | Si |
DataFrames Grandes: Compresion y Chunking
Compresion
La compresion reduce el tamano del archivo en un 60-90% sin perdida de datos. Pandas soporta multiples formatos:
import pandas as pd
import numpy as np
# Crear un 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)
})
# Compresion gzip (mas comun)
df.to_csv('large_data.csv.gz', index=False, compression='gzip')
# Compresion zip
df.to_csv('large_data.zip', index=False, compression='zip')
# Compresion bz2 (mas pequeno pero mas lento)
df.to_csv('large_data.csv.bz2', index=False, compression='bz2')
# Zstandard (rapido, buena relacion -- requiere paquete zstandard)
df.to_csv('large_data.csv.zst', index=False, compression='zstd')| Compresion | Extension | Velocidad | Reduccion de Tamano | Lectura |
|---|---|---|---|---|
| Ninguna | .csv | Escritura mas rapida | 0% | pd.read_csv('f.csv') |
| gzip | .csv.gz | Moderada | 70-85% | pd.read_csv('f.csv.gz') |
| zip | .zip | Moderada | 70-85% | pd.read_csv('f.zip') |
| bz2 | .csv.bz2 | Lenta | 75-90% | pd.read_csv('f.csv.bz2') |
| zstd | .csv.zst | Rapida | 70-85% | pd.read_csv('f.csv.zst') |
Pandas infiere automaticamente el formato de compresion a partir de la extension del archivo, por lo que compression='infer' (el valor predeterminado) generalmente funciona.
Chunksize -- Escribir en Lotes
Para DataFrames muy grandes que sobrecargan la memoria, escriba en bloques:
import pandas as pd
import numpy as np
df = pd.DataFrame({
'id': range(5_000_000),
'value': np.random.randn(5_000_000)
})
# Escribir 500,000 filas a la vez
df.to_csv('huge_data.csv', index=False, chunksize=500_000)El parametro chunksize no reduce el tamano final del archivo -- controla cuantas filas se escriben en disco a la vez. Esto puede ayudar a reducir el uso maximo de memoria durante la operacion de escritura.
Escribir en un String o Buffer
No siempre se escribe en un archivo. A veces necesita la CSV como string para una llamada API, una insercion en base de datos o procesamiento en memoria:
import pandas as pd
df = pd.DataFrame({
'name': ['Alice', 'Bob'],
'score': [85, 92]
})
# Obtener CSV como string
csv_string = df.to_csv(index=False)
print(csv_string)
# name,score
# Alice,85
# Bob,92Escribir en StringIO o 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 respuestas HTTP, subidas a S3)
byte_buffer = BytesIO()
df.to_csv(byte_buffer, index=False, encoding='utf-8')
csv_bytes = byte_buffer.getvalue()Este patron es comun cuando se suben datos CSV a almacenamiento en la nube (S3, GCS) sin crear un archivo local.
Agregar a un CSV Existente
Para agregar filas a un archivo existente sin sobrescribirlo, use mode='a' y header=False:
import pandas as pd
# Primer lote -- escribir con encabezado
df1 = pd.DataFrame({'name': ['Alice'], 'score': [85]})
df1.to_csv('results.csv', index=False)
# Segundo lote -- agregar sin duplicar el encabezado
df2 = pd.DataFrame({'name': ['Bob', 'Charlie'], 'score': [92, 78]})
df2.to_csv('results.csv', mode='a', header=False, index=False)El archivo resultante tiene una fila de encabezado seguida de las tres filas de datos. Omitir header=False insertaria una segunda linea de encabezado en medio de los datos.
Comillas y Escape
Los campos que contienen el delimitador, saltos de linea o comillas necesitan comillas adecuadas. Pandas maneja esto automaticamente, pero puede controlar el comportamiento:
import pandas as pd
import csv
df = pd.DataFrame({
'name': ['O\'Brien', 'Smith, Jr.', 'Alice "Ace" Wong'],
'notes': ['Contiene apostrofe', 'Contiene coma', 'Contiene comillas']
})
# Predeterminado: comillas solo cuando es necesario (QUOTE_MINIMAL)
df.to_csv('minimal.csv', index=False)
# Comillas en todos los campos
df.to_csv('all_quoted.csv', index=False, quoting=csv.QUOTE_ALL)
# Comillas solo en campos no numericos
df.to_csv('nonnumeric.csv', index=False, quoting=csv.QUOTE_NONNUMERIC)Comparacion de Formatos de Exportacion: to_csv() vs to_excel() vs to_parquet()
Elegir el formato de exportacion correcto depende de quien consume el archivo y que tan grande es:
| Caracteristica | to_csv() | to_excel() | to_parquet() |
|---|---|---|---|
| Formato de archivo | Texto plano | Binario (xlsx) | Binario (columnar) |
| Legible por humanos | Si | Via Excel/Sheets | No |
| Tamano de archivo (1M filas) | ~50-100 MB | ~30-60 MB | ~5-15 MB |
| Velocidad de escritura | Rapida | Lenta | Rapida |
| Velocidad de lectura | Moderada | Lenta | Muy rapida |
| Preservacion de tipos | No (todo strings) | Parcial | Completa |
| Requiere biblioteca extra | No | openpyxl | pyarrow / fastparquet |
| Soporte de compresion | gzip, zip, bz2, zstd | Integrado | Integrado (snappy, gzip) |
| Mejor para | Interoperabilidad, APIs, compartir rapido | Usuarios de negocio, usuarios de Excel | Pipelines de analisis, big data |
Regla general: Use CSV para compartir datos con usuarios no tecnicos o sistemas externos. Use Parquet para pipelines internos donde la velocidad y la fidelidad de tipos importan. Use Excel cuando el destinatario necesite formato o multiples hojas.
Errores Comunes y Como Evitarlos
1. Columna de Indice No Deseada
La queja mas frecuente. Siempre pase index=False a menos que su indice contenga datos significativos:
# Incorrecto -- agrega una columna misteriosa "Unnamed: 0" al leer
df.to_csv('data.csv')
# Correcto
df.to_csv('data.csv', index=False)2. Columnas Sin Nombre al Leer
Si exporto con el indice y luego lee el archivo, obtiene una columna Unnamed: 0:
import pandas as pd
# Leer un CSV que fue exportado con indice
df = pd.read_csv('data.csv', index_col=0) # indicar a read_csv cual columna es el indice3. Perdida de Precision en Fecha/Hora
Sin date_format, las columnas de fecha/hora se exportan como marcas de tiempo completas incluyendo microsegundos. Controle esto 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 Redondeo con Flotantes
Los numeros de punto flotante pueden producir digitos finales 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.305. Tipos Mixtos en una Columna
Si una columna tiene tipos mixtos (enteros y strings), to_csv() convierte todo a strings. Verifique sus tipos de datos antes de exportar:
import pandas as pd
df = pd.DataFrame({'id': [1, 2, 'three']})
print(df.dtypes)
# id object <-- tipo mixto
# Limpiar antes de exportar
df['id'] = pd.to_numeric(df['id'], errors='coerce')
df.to_csv('clean.csv', index=False)Visualice Sus Datos Antes de Exportar con PyGWalker
Antes de exportar un DataFrame a CSV, es util verificar que los datos se vean correctos. PyGWalker (opens in a new tab) convierte cualquier DataFrame de Pandas en una interfaz visual interactiva dentro de Jupyter Notebook -- arrastre y suelte columnas para crear graficos sin escribir codigo de visualizacion:
import pandas as pd
import pygwalker as pyg
df = pd.read_csv('raw_data.csv')
# Explorar visualmente antes de exportar
walker = pyg.walk(df)
# Una vez satisfecho, exportar
df.to_csv('verified_export.csv', index=False, encoding='utf-8-sig')Este flujo de trabajo detecta problemas como valores nulos inesperados, valores atipicos o tipos de datos incorrectos antes de que lleguen a su consumidor CSV.
FAQ
Como exporto un DataFrame de Pandas a CSV sin el indice?
Pase index=False a to_csv(): df.to_csv('file.csv', index=False). Esto evita que el indice de filas se escriba como la primera columna. Al leer el archivo de vuelta, no vera una columna extra Unnamed: 0.
Como manejo caracteres especiales y codificacion al exportar a CSV?
Use encoding='utf-8-sig' si el CSV necesita abrirse correctamente en Microsoft Excel con caracteres no ASCII (letras acentuadas, texto CJK). Para sistemas estandar y APIs, el encoding='utf-8' predeterminado funciona. Para sistemas heredados, use la codificacion especifica que requieran (latin-1, shift_jis, etc.).
Como comprimo un archivo CSV grande al exportar desde Pandas?
Agregue una extension de compresion al nombre del archivo y Pandas se encarga del resto: df.to_csv('data.csv.gz', index=False) crea un archivo comprimido con gzip. Tambien puede establecer compression='gzip', 'zip', 'bz2' o 'zstd' explicitamente. Los archivos comprimidos son tipicamente 70-90% mas pequenos y pueden leerse directamente con pd.read_csv().
Puedo agregar datos a un archivo CSV existente en lugar de sobrescribirlo?
Si. Use mode='a' y header=False: df.to_csv('file.csv', mode='a', header=False, index=False). mode='a' abre el archivo para agregar, y header=False evita escribir un encabezado duplicado en medio del archivo.
Cual es la diferencia entre to_csv() y to_parquet() en Pandas?
to_csv() produce un archivo de texto legible por humanos pero pierde informacion de tipos (todo se convierte en strings). to_parquet() crea un archivo binario compacto que preserva los tipos de datos (enteros, flotantes, fechas), se lee 5-10x mas rapido y es 5-10x mas pequeno. Use CSV para compartir con usuarios no tecnicos o sistemas externos. Use Parquet para pipelines de datos internos donde el rendimiento y la fidelidad de tipos importan.
Conclusion
DataFrame.to_csv() es la forma estandar de exportar datos de Pandas a archivos CSV. Para exportaciones limpias, siempre pase index=False. Use encoding='utf-8-sig' cuando la compatibilidad con Excel sea importante. Comprima archivos grandes con gzip o zstd para reducir el tamano en un 70-90%. Controle la precision decimal con float_format, maneje valores faltantes con na_rep y agregue a archivos existentes con mode='a'. Para pipelines de datos donde la preservacion de tipos y la velocidad importan, considere to_parquet() en su lugar. Antes de exportar, verifique sus datos visualmente con herramientas como PyGWalker para detectar problemas temprano.