Pandas DataFrame a CSV: Guia Completa de to_csv()
Actualizado el
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.
- Runcell Science: alternativa open source a Claude Science para investigación
- Cómo evitar que Mac se duerma: mantener Codex, Claude Code y agentes de IA corriendo
- OpenClaw vs ZeroClaw vs Pi Agent vs Nanobot: ¿Qué stack de agentes de IA deberías elegir en 2026?
- Cómo Claude Code analiza notebooks de Jupyter en Data Science: lo que sí hace y lo que no
- Claude Code routines: qué son y por qué importan los cron jobs de agentes de IA
- Claude Code Desktop Bypass Permissions: cómo activarlo
- Cómo Construir Dos Agentes en Python con el Protocolo A2A de Google - Tutorial Paso a Paso
- Las 10 principales bibliotecas de visualización de datos en Python que crecen en 2025
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.