mygems

Cómo combinar varios archivos CSV en uno solo

Concatenar alinea las columnas por posición, así que un encabezado en otro orden arruina el resultado sin avisar. Aprende a unir por nombre y a verificarlo.

Por uos ·

Si los archivos tienen columnas idénticas en el mismo orden, la forma correcta más rápida de combinarlos es una línea de shell que conserva el primer encabezado y descarta los demás:

head -n 1 first.csv > merged.csv
tail -q -n +2 *.csv >> merged.csv

Todo lo demás en esta página existe porque esa suposición de columnas idénticas en el mismo orden es falsa mucho más a menudo de lo que la gente espera, y el fallo es silencioso. Una combinación que desalinea dos columnas produce un archivo que se abre bien, se ve bien y está mal.

Primero, comprueba si los encabezados coinciden

Hazlo antes de combinar, no después. Cada problema que sigue es una variación de este.

for f in *.csv; do echo "$f: $(head -n 1 "$f")"; done

Busca cuatro cosas en la salida:

  • Distinto orden de columnas. name,email,date en un archivo y name,date,email en otro. Al concatenar, las fechas acaban en la columna de correo y nada se queja.
  • Nombres distintos para el mismo campo. Email, email, E-mail, Email Address. Es habitual cuando los archivos vienen de exportaciones distintas, o de la misma exportación en años distintos.
  • Columnas de más o de menos. Una exportación posterior ganó un campo. Ahora las filas tienen anchos distintos.
  • Una marca de orden de bytes (BOM) en el primer archivo. §BOM§name no es name. Es invisible en cualquier editor y rompe los cruces por nombre de columna.

Si todos los encabezados son idénticos byte a byte, usa la versión de dos líneas de arriba y deja de leer. Si no, concatenar es la herramienta equivocada y necesitas algo que combine por nombre de columna.

Combinar por nombre de columna

DuckDB, si los archivos son grandes o los encabezados difieren

Un solo comando resuelve los dos problemas, el orden distinto de columnas y las columnas que faltan, porque alinea por nombre y no por posición:

duckdb -c "COPY (SELECT * FROM read_csv('*.csv', union_by_name=true, filename=true)) TO 'merged.csv' (HEADER)"

union_by_name=true es lo que hace el trabajo: las columnas se emparejan por encabezado, y un archivo al que le falta una columna recibe NULL en lugar de una fila desplazada. filename=true agrega una columna que registra de qué archivo viene cada fila, algo que vas a querer más a menudo de lo que crees. Es la única forma de responder después "en qué exportación llegó esta fila mala".

DuckDB procesa en flujo, así que el tamaño de los archivos lo limita el disco y no la RAM. Cien archivos que suman varios gigabytes no tienen nada de raro.

Python, si primero tienes que unificar los nombres

Cuando el mismo campo se llama Email en un archivo y E-mail Address en otro, ninguna herramienta puede adivinarlo. Normaliza de forma explícita:

import glob, pandas as pd

rename = {"E-mail Address": "email", "Email": "email"}
frames = []
for path in glob.glob("*.csv"):
    df = pd.read_csv(path, dtype=str)
    df.columns = [c.strip().lstrip("§BOM§") for c in df.columns]
    frames.append(df.rename(columns=rename).assign(source=path))

pd.concat(frames, ignore_index=True).to_csv("merged.csv", index=False)

Dos detalles importan más que la combinación en sí. dtype=str evita que pandas infiera tipos archivo por archivo. Sin eso, una columna de ID de cliente que es numérica en un archivo y alfanumérica en otro sale como una mezcla de 1024 y "01024", y los ceros a la izquierda se pierden para siempre. Y .assign(source=path) es la misma columna de procedencia que DuckDB te da sin esfuerzo.

Power Query, en un escritorio sin terminal

En Excel, Datos → Obtener datos → Desde carpeta apunta a un directorio y combina todos los archivos que hay en él, emparejando por encabezado. Lo hace bien, se actualiza cuando llegan archivos nuevos a la carpeta y es la respuesta correcta para quien va a repetir esta combinación cada mes.

Su límite es el de Excel: el resultado combinado tiene que caber en 1.048.576 filas para llegar a una hoja. Puedes cargarlo en el modelo de datos y olvidarte de la hoja, algo que la mayoría no sabe y que sube el techo bastante.

La diferencia entre anexar y cruzar

"Combinar" significa dos operaciones distintas, y elegir la equivocada te hace perder una tarde.

TienesQuieresOperación
Doce exportaciones mensuales, mismas columnasUn archivo, más filasAnexar (apilar)
Clientes en un archivo, pedidos en otroUn archivo, más columnasCruce (join, emparejar por una clave)

Todo lo anterior es anexar. Un cruce necesita una clave compartida y una decisión sobre qué pasa con las filas sin pareja, y es donde se crean duplicados: una clave que no es única en ambos lados multiplica las filas sin avisar. Si el número de filas tras un cruce es mayor que el de cualquiera de las entradas, eso es lo que pasó.

Para un cruce, SQL es la herramienta honesta:

duckdb -c "COPY (SELECT c.*, o.order_total FROM read_csv('customers.csv') c LEFT JOIN read_csv('orders.csv') o USING (customer_id)) TO 'merged.csv' (HEADER)"

En el teléfono

El escenario realista en el teléfono: un puñado de archivos en Mail o Archivos, tres exportaciones regionales o unos meses de extractos, y ningún portátil hasta el lunes.

Dos cosas ayudan aquí. Anexar archivos con encabezados idénticos es copiar y pegar, siempre que la app pueda pegar un bloque de filas y no una celda a la vez. Y la comprobación que importa, comparar encabezados, es más rápida en el teléfono que en ningún otro sitio: abre cada archivo y lee la fila de arriba.

CSV Editor - Smart CSViPhone y iPad

Abre cada exportación en segundos, pega un rango de filas en otra hoja y escribe de vuelta cada fila al guardar, también en la versión gratuita. Con la inserción de columnas y filas, reconciliar un archivo que ganó un campo es una edición real y no un apaño.

Qué hace

Para más de un puñado de archivos, espera a tener un escritorio. Combinar treinta exportaciones a mano en una pantalla táctil no es buena idea, y la razón es la tasa de errores, no el aburrimiento.

Después de combinar, cuatro comprobaciones

Hazlas siempre. Llevan un minuto y atrapan prácticamente todos los fallos de combinación que importan.

  1. Número de filas. El total combinado debe ser la suma de las filas de cada entrada, menos un encabezado por archivo. wc -l *.csv antes, wc -l merged.csv después.
  2. Número de encabezados. grep -c "^name," merged.csv, o como se llame la primera columna. Más de uno significa que un encabezado terminó como fila de datos.
  3. Ancho de columnas. Todas las filas deben tener el mismo número de campos. Anchos desiguales indican una coma sin comillas en algún sitio, no un fallo de la combinación.
  4. Revisa la frontera. Mira la última fila del primer archivo y la primera del segundo en el resultado. La desalineación se nota ahí primero.

La segunda comprobación tiene su sutileza: si una línea de encabezado acaba en los datos, al ordenar se dispersará por el medio del archivo y luego será muy difícil de encontrar. Atrápala ahora.

CSV File Viewer - Smart CSViPhone y iPad · Android

Ejecuta SQL directamente sobre el archivo combinado, así que un GROUP BY sobre la columna de origen te dice que cada archivo aportó las filas que debía, toda la verificación en una consulta.

Qué hace

Codificación, el fallo que sobrevive a todas las comprobaciones

Los archivos de sistemas distintos suelen estar en codificaciones distintas, y concatenar no convierte nada. Un archivo UTF-8 anexado a uno Windows-1252 produce un archivo que no es ninguno de los dos: los nombres se ven bien en la primera mitad y como é en la segunda.

Convierte antes de combinar, no después:

iconv -f WINDOWS-1252 -t UTF-8 old.csv > old-utf8.csv

file -I *.csv intentará adivinar lo que tienes, aunque adivina mal en archivos cortos. La señal fiable es abrir cada archivo y mirar una fila con algún carácter no ASCII.

Preguntas

¿Cómo combino varios archivos CSV en uno solo?
Si todos los archivos tienen encabezados idénticos byte a byte, conserva el primero y anexa el resto: `head -n 1 first.csv > merged.csv` y luego `tail -q -n +2 *.csv >> merged.csv`. Si los encabezados difieren en orden o contenido, concatenar desalinea las columnas en silencio, así que usa una herramienta que empareje por nombre de columna, como read_csv de DuckDB con union_by_name=true, o Obtener datos desde carpeta de Excel.
¿Por qué mi CSV combinado tiene las columnas en lugares equivocados?
Porque concatenar empareja por posición, no por nombre. Dos archivos con las mismas columnas en distinto orden producen un archivo con los valores desplazados, y no se reporta ningún error. Compara siempre las líneas de encabezado antes de combinar: `for f in *.csv; do echo "$f: $(head -n 1 "$f")"; done`.
¿Cómo combino archivos CSV con columnas distintas?
Empareja por nombre de columna y rellena los huecos. DuckDB lo hace en un solo comando con `union_by_name=true`, dando NULL en la columna que un archivo no tiene. En pandas, `pd.concat` sobre tablas leídas con `dtype=str` hace lo mismo. Los campos que son lo mismo con nombres distintos, Email frente a E-mail Address, hay que renombrarlos antes de forma explícita; ninguna herramienta puede deducirlo.
¿Cómo sé de qué archivo viene cada fila del CSV combinado?
Agrega una columna de procedencia durante la combinación. read_csv de DuckDB acepta `filename=true` y la agrega automáticamente; en pandas, `.assign(source=path)` en cada tabla hace lo mismo. Es la única forma de rastrear después una fila mala hasta su exportación, y convierte la verificación en un solo GROUP BY.
¿Cómo compruebo que la combinación del CSV salió bien?
Cuatro comprobaciones: el número de filas combinadas es la suma de las entradas menos un encabezado por archivo; el texto del encabezado aparece exactamente una vez; todas las filas tienen el mismo número de campos; y la frontera entre el primer y el segundo archivo se ve bien. Un encabezado que terminó como fila de datos es el fallo que conviene atrapar pronto, porque al ordenar se dispersa por el medio del archivo.
¿Por qué se ven mal los caracteres con tilde en la mitad de mi archivo combinado?
Las entradas tenían codificaciones distintas, y anexar no convierte. Un archivo Windows-1252 anexado a uno UTF-8 te deja nombres correctos en una mitad y mojibake en la otra. Convierte primero todo a UTF-8 con `iconv -f WINDOWS-1252 -t UTF-8 old.csv > old-utf8.csv` y luego combina.

uos — Desarrolla CSV Editor y Smart CSV Viewer, y vio cómo una unión desplazaba una columna una posición durante 200.000 filas sin un solo error.