Skip to content

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,95000

Note 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,95000

Firma 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.2

float_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.12

date_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-01

Manejo 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')
CodificacionCuando UsarCompatible con Excel?
utf-8Predeterminado para la mayoria de sistemas, APIs, bases de datosParcial (sin BOM)
utf-8-sigExcel en Windows con texto no ASCIISi
latin-1 / iso-8859-1Sistemas europeos occidentales heredadosSi
shift_jisSistemas japoneses heredadosSi
cp1252Windows europeo occidentalSi

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')
CompresionExtensionVelocidadReduccion de TamanoLectura
Ninguna.csvEscritura mas 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 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,92

Escribir 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:

Caracteristicato_csv()to_excel()to_parquet()
Formato de archivoTexto planoBinario (xlsx)Binario (columnar)
Legible por humanosSiVia Excel/SheetsNo
Tamano de archivo (1M filas)~50-100 MB~30-60 MB~5-15 MB
Velocidad de escrituraRapidaLentaRapida
Velocidad de lecturaModeradaLentaMuy rapida
Preservacion de tiposNo (todo strings)ParcialCompleta
Requiere biblioteca extraNoopenpyxlpyarrow / fastparquet
Soporte de compresiongzip, zip, bz2, zstdIntegradoIntegrado (snappy, gzip)
Mejor paraInteroperabilidad, APIs, compartir rapidoUsuarios de negocio, usuarios de ExcelPipelines 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 indice

3. 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.30

5. 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.

📚