cómo fusionar 200 archivos csv en Python

82

Chicos, aquí tengo 200 archivos csv separados nombrados de SH (1) a SH (200). Quiero combinarlos en un solo archivo csv. ¿Cómo puedo hacerlo?

Arrojar
fuente
3
¿De qué manera los fusionarías? (Concatenar líneas, ...)
Tur1ng
6
¿Cómo quieres que se fusionen? Cada línea de un archivo CSV es una fila. Entonces, una opción simple es concatenar todos los archivos juntos.
Jon-Eric
Cada archivo tiene dos columnas. Quiero fusionarlos en un solo archivo con dos columnas consecutivas.
Chuck
1
@Chuck: ¿Qué tal si tomas todas las respuestas en tus comentarios (a la pregunta y a las respuestas) y actualizas tu pregunta?
tumultous_rooster
1
Esta pregunta debe ser nombrado "Cómo concat ..." en lugar de "cómo se funden ..."
colidyre

Respuestas:

92

Como dijo ghostdog74, pero esta vez con encabezados:

fout=open("out.csv","a")
# first file:
for line in open("sh1.csv"):
    fout.write(line)
# now the rest:    
for num in range(2,201):
    f = open("sh"+str(num)+".csv")
    f.next() # skip the header
    for line in f:
         fout.write(line)
    f.close() # not really needed
fout.close()
nostálgico
fuente
11
puede usar f.__next__()en su lugar si está f.next()en python3.x.
tsveti_iko
5
Solo una nota: se puede usar la with opensintaxis y evitar la manipulación manual .close()de los archivos.
FatihAkici
2
¿Cuál es la diferencia entre f.next()y f.__next__()? cuando uso el primero, obtuve'_io.TextIOWrapper' object has no attribute 'next'
Jason Goal
antes de fout.write(line)que haría:if line[-1] != '\n': line += '\n'
shisui
65

¿Por qué no puedes simplemente sed 1d sh*.csv > merged.csv?

¡A veces ni siquiera tienes que usar Python!

blinsay
fuente
21
En Windows, C: \> copiar * .csv merged.csv
ataque aéreo
5
Copie la información del encabezado de un archivo: sed -n 1p some_file.csv> merged_file.csv Copie todo menos la última línea de todos los demás archivos: sed 1d * .csv >> merged_file.csv
behas
3
@blinsay Sin embargo, también agrega el encabezado en cada archivo CSV al archivo combinado.
Mina
5
¿Cómo se usa este comando sin copiar la información del encabezado para cada archivo subsiguiente después del primero? Parece que la información del encabezado aparece repetidamente.
Joe
2
¡Esto es genial si no necesita quitar el encabezado!
Blairg23
50

Use la respuesta aceptada de StackOverflow para crear una lista de archivos csv que desea agregar y luego ejecute este código:

import pandas as pd
combined_csv = pd.concat( [ pd.read_csv(f) for f in filenames ] )

Y si desea exportarlo a un solo archivo csv, use esto:

combined_csv.to_csv( "combined_csv.csv", index=False )
Scottlittle
fuente
@ wisty, @ Andy, suponga que todos los archivos tienen títulos para cada fila, algunas filas con títulos diferentes. No hay encabezados para las 2 columnas de cada archivo. ¿Cómo se puede fusionar, de modo que para cada archivo solo se agregue una columna?
Gathide
¿A dónde se exporta el archivo?
@ dirtysocks45, cambié la respuesta para hacerlo más explícito.
scottlittle
agregar ordenamiento: combinado_csv = pd.concat ([pd.read_csv (f) para f en nombres de archivo], ordenar = Falso)
sailfish009
16
fout=open("out.csv","a")
for num in range(1,201):
    for line in open("sh"+str(num)+".csv"):
         fout.write(line)    
fout.close()
ghostdog74
fuente
12

Solo voy a ver otro ejemplo de código en la canasta

from glob import glob

with open('singleDataFile.csv', 'a') as singleFile:
    for csvFile in glob('*.csv'):
        for line in open(csvFile, 'r'):
            singleFile.write(line)
Norfeldt
fuente
2
@Andy No veo la diferencia entre stackoverflow que me recuerda que vote a favor una respuesta y que yo les recuerde a las personas que compartan su agradecimiento (votando) si mi respuesta les resultó útil. Sé que esto no es Facebook y no soy un cazador de me gusta ..
Norfeldt
1
Se ha discutido anteriormente y cada vez se ha considerado inaceptable.
Andy
10

Depende de lo que quiera decir con "fusión": ¿tienen las mismas columnas? ¿Tienen encabezados? Por ejemplo, si todos tienen las mismas columnas y no tienen encabezados, una simple concatenación es suficiente (abra el archivo de destino para escribir, recorra las fuentes abriendo cada una para leer, use shutil.copyfileobj de la fuente abierta para lectura en la destino abierto para escritura, cierre la fuente, siga repitiendo - use la withdeclaración para hacer el cierre en su nombre). Si tienen las mismas columnas, pero también encabezados, necesitará un readlineen cada archivo de origen, excepto el primero, después de abrirlo para leerlo antes de copiarlo en el destino, para omitir la línea de encabezados.

Si los archivos CSV no tienen todos las mismas columnas, entonces necesita definir en qué sentido los está "fusionando" (como un SQL JOIN? U "horizontalmente" si todos tienen el mismo número de líneas? Etc., etc. ) - es difícil para nosotros adivinar lo que quiere decir en ese caso.

Alex Martelli
fuente
Cada archivo tiene dos columnas con encabezados. Quiero combinarlos en un solo archivo con dos columnas consecutivamente.
Chuck
3

Si el CSV combinado se va a usar en Python, solo utilícelo globpara obtener una lista de los archivos a los que pasar a fileinput.input()través del filesargumento, luego use el csvmódulo para leerlo todo de una vez.

Ignacio Vázquez-Abrams
fuente
3

Un ligero cambio en el código anterior, ya que en realidad no funciona correctamente.

Debería ser como sigue ...

from glob import glob

with open('main.csv', 'a') as singleFile:
    for csv in glob('*.csv'):
        if csv == 'main.csv':
            pass
        else:
            for line in open(csv, 'r'):
                singleFile.write(line)
Sumadores
fuente
3

Muy fácil de combinar todos los archivos en un directorio y fusionarlos

import glob
import csv


# Open result file
with open('output.txt','wb') as fout:
    wout = csv.writer(fout,delimiter=',') 
    interesting_files = glob.glob("*.csv") 
    h = True
    for filename in interesting_files: 
        print 'Processing',filename 
        # Open and process file
        with open(filename,'rb') as fin:
            if h:
                h = False
            else:
                fin.next()#skip header
            for line in csv.reader(fin,delimiter=','):
                wout.writerow(line)
varun
fuente
3

Si está trabajando en linux / mac, puede hacerlo.

from subprocess import call
script="cat *.csv>merge.csv"
call(script,shell=True)
soleado
fuente
2

O, simplemente podrías hacer

cat sh*.csv > merged.csv
Nanashi No Gombe
fuente
1

Puede importar csv y luego recorrer todos los archivos CSV leyéndolos en una lista. Luego, vuelva a escribir la lista en el disco.

import csv

rows = []

for f in (file1, file2, ...):
    reader = csv.reader(open("f", "rb"))

    for row in reader:
        rows.append(row)

writer = csv.writer(open("some.csv", "wb"))
writer.writerows("\n".join(rows))

Lo anterior no es muy robusto ya que no maneja errores ni cierra ningún archivo abierto. Esto debería funcionar independientemente de que los archivos individuales tengan una o más filas de datos CSV en ellos. Además, no ejecuté este código, pero debería darte una idea de qué hacer.

cnobile
fuente
1

Sobre la solución que hizo @Adders y luego mejorada por @varun, implementé algunas pequeñas mejoras y dejé todo el CSV combinado con solo el encabezado principal:

from glob import glob

filename = 'main.csv'

with open(filename, 'a') as singleFile:
    first_csv = True
    for csv in glob('*.csv'):
        if csv == filename:
            pass
        else:
            header = True
            for line in open(csv, 'r'):
                if first_csv and header:
                    singleFile.write(line)
                    first_csv = False
                    header = False
                elif header:
                    header = False
                else:
                    singleFile.write(line)
    singleFile.close()

¡¡¡Atentamente!!!

Fabián Miranda Muñoz
fuente
1

Simplemente puede usar la csvbiblioteca incorporada . Esta solución funcionará incluso si algunos de sus archivos CSV tienen nombres de columna o encabezados ligeramente diferentes, a diferencia de las otras respuestas más votadas.

import csv
import glob


filenames = [i for i in glob.glob("SH*.csv")]
header_keys = []
merged_rows = []

for filename in filenames:
    with open(filename) as f:
        reader = csv.DictReader(f)
        merged_rows.extend(list(reader))
        header_keys.extend([key for key in reader.fieldnames if key not in header_keys])

with open("combined.csv", "w") as f:
    w = csv.DictWriter(f, fieldnames=header_keys)
    w.writeheader()
    w.writerows(merged_rows)

El archivo combinado contendrá todas las columnas posibles ( header_keys) que se pueden encontrar en los archivos. Cualquier columna ausente en un archivo se representaría como en blanco / vacía (pero conservando el resto de los datos del archivo).

Nota:

  • Esto no funcionará si sus archivos CSV no tienen encabezados. En ese caso, aún puede usar la csvbiblioteca, pero en lugar de usar DictReader& DictWriter, tendrá que trabajar con el reader& básico writer.
  • Esto puede generar problemas cuando se trata de datos masivos, ya que la totalidad del contenido se almacena en la memoria ( merged_rowslista).
shad0w_wa1k3r
fuente
0

Modifiqué lo que @wisty dijo para trabajar con python 3.x, para aquellos de ustedes que tienen problemas de codificación, también uso el módulo os para evitar la codificación dura

import os 
def merge_all():
    dir = os.chdir('C:\python\data\\')
    fout = open("merged_files.csv", "ab")
    # first file:
    for line in open("file_1.csv",'rb'):
        fout.write(line)
    # now the rest:
    list = os.listdir(dir)
    number_files = len(list)
    for num in range(2, number_files):
        f = open("file_" + str(num) + ".csv", 'rb')
        f.__next__()  # skip the header
        for line in f:
            fout.write(line)
        f.close()  # not really needed
    fout.close()
Maryam Pashmi
fuente
0

Aquí hay un guión:

  • Csv concatenación de archivos con el nombre SH1.csvdeSH200.csv
  • Manteniendo los encabezados
import glob
import re

# Looking for filenames like 'SH1.csv' ... 'SH200.csv'
pattern = re.compile("^SH([1-9]|[1-9][0-9]|1[0-9][0-9]|200).csv$")
file_parts = [name for name in glob.glob('*.csv') if pattern.match(name)]

with open("file_merged.csv","wb") as file_merged:
    for (i, name) in enumerate(file_parts):
        with open(name, "rb") as file_part:
            if i != 0:
                next(file_part) # skip headers if not first file
            file_merged.write(file_part.read())
x0s
fuente
0

Actualizando la respuesta de wisty para python3

fout=open("out.csv","a")
# first file:
for line in open("sh1.csv"):
    fout.write(line)
# now the rest:    
for num in range(2,201):
    f = open("sh"+str(num)+".csv")
    next(f) # skip the header
    for line in f:
         fout.write(line)
    f.close() # not really needed
fout.close()
ishandutta2007
fuente
0

Digamos que tiene 2 csvarchivos como estos:

csv1.csv:

id,name
1,Armin
2,Sven

csv2.csv:

id,place,year
1,Reykjavik,2017
2,Amsterdam,2018
3,Berlin,2019

y desea que el resultado sea como este csv3.csv:

id,name,place,year
1,Armin,Reykjavik,2017
2,Sven,Amsterdam,2018
3,,Berlin,2019

Luego, puede usar el siguiente fragmento para hacerlo:

import csv
import pandas as pd

# the file names
f1 = "csv1.csv"
f2 = "csv2.csv"
out_f = "csv3.csv"

# read the files
df1 = pd.read_csv(f1)
df2 = pd.read_csv(f2)

# get the keys
keys1 = list(df1)
keys2 = list(df2)

# merge both files
for idx, row in df2.iterrows():
    data = df1[df1['id'] == row['id']]

    # if row with such id does not exist, add the whole row
    if data.empty:
        next_idx = len(df1)
        for key in keys2:
            df1.at[next_idx, key] = df2.at[idx, key]

    # if row with such id exists, add only the missing keys with their values
    else:
        i = int(data.index[0])
        for key in keys2:
            if key not in keys1:
                df1.at[i, key] = df2.at[idx, key]

# save the merged files
df1.to_csv(out_f, index=False, encoding='utf-8', quotechar="", quoting=csv.QUOTE_NONE)

Con la ayuda de un bucle, puede lograr el mismo resultado para varios archivos que en su caso (200 archivos csv).

tsveti_iko
fuente
0

Si los archivos no están numerados en orden, adopte el método sin complicaciones a continuación: Python 3.6 en una máquina con Windows:

import pandas as pd
from glob import glob

interesting_files = glob("C:/temp/*.csv") # it grabs all the csv files from the directory you mention here

df_list = []
for filename in sorted(interesting_files):

df_list.append(pd.read_csv(filename))
full_df = pd.concat(df_list)

# save the final file in same/different directory:
full_df.to_csv("C:/temp/merged_pandas.csv", index=False)
Azadeh Feizpour
fuente
0

Una función fácil de usar:

def csv_merge(destination_path, *source_paths):
'''
Merges all csv files on source_paths to destination_path.
:param destination_path: Path of a single csv file, doesn't need to exist
:param source_paths: Paths of csv files to be merged into, needs to exist
:return: None
'''
with open(destination_path,"a") as dest_file:
    with open(source_paths[0]) as src_file:
        for src_line in src_file.read():
            dest_file.write(src_line)
    source_paths.pop(0)
    for i in range(len(source_paths)):
        with open(source_paths[i]) as src_file:
            src_file.next()
            for src_line in src_file:
                 dest_file.write(src_line)
Ken Shibata
fuente
0
import pandas as pd
import os

df = pd.read_csv("e:\\data science\\kaggle assign\\monthly sales\\Pandas-Data-Science-Tasks-master\\SalesAnalysis\\Sales_Data\\Sales_April_2019.csv")
files = [file for file in  os.listdir("e:\\data science\\kaggle assign\\monthly sales\\Pandas-Data-Science-Tasks-master\\SalesAnalysis\\Sales_Data")
for file in files:
    print(file)

all_data = pd.DataFrame()
for file in files:
    df=pd.read_csv("e:\\data science\\kaggle assign\\monthly sales\\Pandas-Data-Science-Tasks-master\\SalesAnalysis\\Sales_Data\\"+file)
    all_data = pd.concat([all_data,df])
    all_data.head()
Sunit Deogam
fuente