Leer datos: CSV, Excel, Parquet
pd.read_csv(): el verbo más usado
pd.read_csv() es la puerta de entrada de casi todo análisis. Sus defaults funcionan en el 80 % de los casos, pero el otro 20 % requiere conocer cinco argumentos clave:
import pandas as pd
df = pd.read_csv("data/ventas.csv")
df.head()Listo. pandas detecta automáticamente delimitador, tipos y encoding. Para datos sencillos, esto basta.
Cuando los defaults fallan, las cinco opciones que de verdad importan:
| Argumento | Para qué |
|---|---|
sep |
Delimitador (default ,. Usa ; para CSVs europeos) |
dtype |
Forzar tipo por columna |
parse_dates |
Convertir columnas a fechas automáticamente |
encoding |
Codificación del archivo (UTF-8 por defecto) |
na_values |
Qué strings se consideran NA |
Ejemplo combinando todas:
df = pd.read_csv(
"data/ventas.csv",
sep=";", # punto y coma (formato europeo)
dtype={"codigo_postal": "string"}, # forzar a string (no perder ceros iniciales)
parse_dates=["fecha_venta", "fecha_envio"],
encoding="latin-1",
na_values=["", "N/A", "-", "?"]
)Tipos por columna con dtype
pandas adivina los tipos. A veces se equivoca:
- Códigos postales como
"01234"los convierte a número1234(perdiendo el cero). - Identificadores muy largos los puede pasar a float perdiendo precisión.
- Columnas con texto y números mezclados quedan como
object(genérico).
dtype te permite forzar:
df = pd.read_csv(
"data/clientes.csv",
dtype={
"codigo_postal": "string",
"id_cliente": "string",
"edad": "Int64", # Int64 con I mayúscula: soporta NA
"ingresos": "float64",
"activo": "boolean"
}
)Tipos modernos que conviene conocer:
"string": strings nativos. Reemplaza alobjecttradicional."Int64"(con I mayúscula), entero que soporta NA. Elint64clásico no."Float64": análogo. Soportapd.NAcomo NA explícito."boolean": booleano que soporta NA.
Para versiones de pandas 2.0+, considera usar dtype_backend="pyarrow":
df = pd.read_csv("data/ventas.csv", dtype_backend="pyarrow")pyarrow backend es mucho más rápido, usa menos memoria, y trata NAs consistentemente. Es la dirección hacia donde va pandas.
Parsing de fechas
Por defecto, las columnas de fecha quedan como object. Para convertirlas:
df = pd.read_csv("data/ventas.csv", parse_dates=["fecha"])Si la fecha está en formato europeo (dd/mm/yyyy), parse_dates puede fallar o interpretar mal (01/03/2024 lo parsea como 3 de enero en lugar de 1 de marzo). Hay que ser explícito:
df = pd.read_csv(
"data/ventas.csv",
parse_dates=["fecha"],
date_format="%d/%m/%Y"
)date_format usa los códigos strftime (%Y año, %m mes, %d día, %H hora, etc.).
Para combinar columnas de fecha (year, month, day separadas):
df["fecha"] = pd.to_datetime(df[["year", "month", "day"]])pd.to_datetime() es el conversor universal, admite strings, columnas combinadas, números epoch, lo que sea.
Encoding: datos europeos
UTF-8 es el default sensato. Pero archivos antiguos de Windows suelen estar en latin-1 (también llamado cp1252):
df = pd.read_csv("data/clientes.csv", encoding="latin-1")Síntoma típico: acentos que aparecen como ñ en lugar de ñ. Solución: cambiar encoding. Si dudas, prueba primero "utf-8", luego "latin-1", luego "cp1252". Uno de los tres suele funcionar.
Para CSVs con separador europeo (punto y coma) y decimal con coma:
df = pd.read_csv(
"data/ventas.csv",
sep=";",
decimal=",",
thousands="."
)decimal="," interpreta los decimales con coma. thousands="." ignora el punto como separador de miles. Tres argumentos para no pelearse con datos en formato español.
read_excel: Excel multi-hoja
Para archivos .xlsx:
df = pd.read_excel("data/ventas.xlsx", sheet_name="2024")Argumentos útiles:
sheet_name="...": qué hoja. Acepta nombre o índice (0-based).sheet_name=None: devuelve un diccionario{hoja: DataFrame}con todas.header=0: qué fila contiene los nombres (default: primera).skiprows=2: saltar las primeras N filas (útil cuando hay título o metadata arriba).usecols="B:G": solo columnas B a G.
Para leer todas las hojas de un Excel:
hojas = pd.read_excel("data/ventas.xlsx", sheet_name=None)
hojas.keys() # nombres de las hojas
hojas["2024"] # DataFrame de esa hojaread_excel necesita el paquete openpyxl para archivos .xlsx (o xlrd para .xls antiguos). Si uv no lo tiene, añádelo:
uv add openpyxlParquet: el formato moderno
CSV es ubicuo pero ineficiente: texto plano, sin tipos, lento de parsear con archivos grandes. Parquet es un formato columnar binario que resuelve esto:
# Escribir
df.to_parquet("data/ventas.parquet")
# Leer
df = pd.read_parquet("data/ventas.parquet")Ventajas:
- 10-100× más pequeño que CSV (compresión columnar).
- 5-10× más rápido de leer/escribir.
- Preserva tipos: los datetime quedan datetime, no strings.
- Soporta NA correctamente.
Cuándo usarlo:
- Datos intermedios en pipelines (entre un script y el siguiente).
- Datasets grandes que abres muchas veces.
- Compartir entre Python y R (el paquete
arrowen R lee Parquet nativo).
Cuándo NO:
- Compatibilidad con sistemas legacy que solo aceptan CSV.
- Datos que un humano va a abrir en Excel.
Para Parquet, necesitas pyarrow:
uv add pyarrowpyarrow es además el backend recomendado para muchos paquetes modernos. Vale la pena tenerlo.
Lectura por chunks: archivos grandes
CSVs de varios GB no caben en memoria. pd.read_csv los maneja con chunksize:
chunks = pd.read_csv("data/big.csv", chunksize=100_000)
# chunks es un iterador. Procesas un trozo a la vez.
totales = []
for chunk in chunks:
chunk_filt = chunk[chunk["ventas"] > 1000]
totales.append(chunk_filt["ventas"].sum())
total_general = sum(totales)Patrón: leer en bloques, procesar cada bloque, agregar resultados. Es el equivalente al streaming en memoria limitada.
Alternativas más modernas para datos grandes:
polars: DataFrame backend nativo en Rust, 10-100× más rápido que pandas en operaciones grandes. Si tus datos no entran en pandas, polars suele entrar.duckdb: base de datos analítica embebida. Puedes hacer SQL sobre Parquet/CSV directamente sin cargar todo a memoria.pyarrow+pyarrow.dataset, el sistema moderno de Apache Arrow para datasets enormes particionados.
Para análisis ad-hoc < 1 GB, pandas basta. Para más, considera estas alternativas.
Trampas habituales
- CSV que abrió Excel. Excel modifica datos silenciosamente: cambia separadores, transforma fechas según el locale, pierde ceros iniciales. Si recibes un CSV que pasó por Excel, ábrelo en un editor de texto antes de cargarlo a pandas, confirma que es lo que esperas.
- Encoding incorrecto que parece funcionar. A veces el archivo se lee sin errores pero los acentos aparecen mal. Comprueba siempre
df["columna_con_acentos"].head()después de leer. parse_datesque falla silenciosamente. Si la fecha no se puede parsear, queda comoobjectsin warning fuerte. Verifica condf.dtypesque la columna esdatetime64[ns].- Olvidar
low_memory=Falsecon archivos heterogéneos. Por defecto,read_csvlee en chunks para ahorrar memoria. Si una columna empieza con números pero después aparecen strings, pandas la tipará comoobjectcon un warning.low_memory=Falselee todo de una vez y suele resolverlo (aunque usa más RAM).
En la siguiente entrega
Has aprendido a traer datos. La siguiente pieza es seleccionar partes de un DataFrame, .loc, .iloc, boolean indexing. Es la operación más frecuente en análisis y donde más errores se cometen al venir de R. Lo siguiente (en la próxima sesión).