cách hợp nhất 200 tệp csv bằng Python


82

Các bạn ơi, mình ở đây có 200 tệp csv riêng biệt có tên từ SH (1) đến SH (200). Tôi muốn hợp nhất chúng thành một tệp csv duy nhất. Tôi làm nó như thế nào?


3
Bạn sẽ hợp nhất chúng theo cách nào? (Nối các dòng, ...)
tur1ng

6
Bạn muốn chúng hợp nhất như thế nào? Mỗi dòng trong tệp CSV là một hàng. Vì vậy, một tùy chọn đơn giản là chỉ cần nối tất cả các tệp lại với nhau.
Jon-Eric

Mỗi tệp có hai cột. Tôi muốn hợp nhất chúng thành một tệp duy nhất có hai cột liên tiếp.
Chuck

1
@Chuck: Làm thế nào về việc nhận tất cả các câu trả lời trong nhận xét của bạn (cho câu hỏi và câu trả lời) và cập nhật câu hỏi của bạn?
tumultous_rooster

1
Câu hỏi này nên được đặt tên là "Làm thế nào để concat ..." thay vì "làm thế nào để hợp nhất ..."
colidyre

Câu trả lời:


92

Như ghostdog74 đã nói, nhưng lần này với tiêu đề:

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()

11
bạn có thể sử dụng f.__next__()thay thế nếu f.next()trong python3.x.
tsveti_iko

5
Chỉ cần lưu ý: Người ta có thể sử dụng with opencú pháp và tránh nhập .close()các tệp theo cách thủ công .
FatihAkici

2
sự khác biệt giữa f.next()và là f.__next__()gì? khi tôi sử dụng cái cũ, tôi nhận được'_io.TextIOWrapper' object has no attribute 'next'
Mục tiêu của Jason

trước khi fout.write(line)tôi làm:if line[-1] != '\n': line += '\n'
shisui

64

Tại sao bạn không thể chỉ sed 1d sh*.csv > merged.csv?

Đôi khi bạn thậm chí không cần phải sử dụng python!


21
Trên windows, C: \> copy * .csv merge.csv
không kích

5
Sao chép thông tin tiêu đề từ một tệp: sed -n 1p some_file.csv> merge_file.csv Sao chép tất cả trừ dòng cuối cùng từ tất cả các tệp khác: sed 1d * .csv >> merge_file.csv
hoạt động

3
@blinsay Nó cũng thêm tiêu đề trong mỗi tệp CSV vào tệp đã hợp nhất.
Mina

5
Làm cách nào để bạn sử dụng lệnh này mà không sao chép thông tin tiêu đề cho từng tệp tiếp theo sau tệp đầu tiên? Tôi dường như nhận được thông tin tiêu đề bật lên liên tục.
Joe

2
Điều này thật tuyệt nếu bạn không cần xóa tiêu đề!
Blairg23

50

Sử dụng câu trả lời StackOverflow được chấp nhận để tạo danh sách các tệp csv mà bạn muốn nối thêm và sau đó chạy mã này:

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

Và nếu bạn muốn xuất nó thành một tệp csv, hãy sử dụng cái này:

combined_csv.to_csv( "combined_csv.csv", index=False )

@ wisty, @ Andy, giả sử tất cả các tệp đều có tiêu đề cho mỗi hàng - một số hàng có tiêu đề khác nhau. Không có tiêu đề cho 2 cột trong mỗi tệp. Làm thế nào một người có thể hợp nhất, sao cho mỗi tệp chỉ có một cột được thêm vào.
Gathide

Tệp được xuất sang đâu?

@ dirtysocks45, tôi đã thay đổi câu trả lời để làm cho điều này rõ ràng hơn.
scottlittle

thêm sắp xếp: merge_csv = pd.concat ([pd.read_csv (f) cho f trong tên tệp], sort = False)
buồmfish009

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()

12

Tôi chỉ sẽ xem qua một ví dụ mã khác trong giỏ

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)

2
@Andy Tôi không thấy sự khác biệt giữa stackoverflow nhắc tôi bỏ phiếu cho câu trả lời và tôi nhắc mọi người chia sẻ sự đánh giá cao của họ (bằng cách bỏ phiếu) nếu họ thấy câu trả lời của tôi hữu ích. Tôi biết rằng đây không phải là Facebook và tôi không phải là một kẻ săn like ..
Norfeldt

1
Nó đã được thảo luận trước đây , và mỗi lần nó được coi là không thể chấp nhận được.
Andy

10

Nó phụ thuộc vào ý bạn khi "hợp nhất" - chúng có các cột giống nhau không? Chúng có tiêu đề không? Ví dụ: nếu tất cả chúng đều có cùng cột và không có tiêu đề, thì nối đơn giản là đủ (mở tệp đích để ghi, lặp qua các nguồn đang mở để đọc, sử dụng shutil.copyfileobj từ nguồn mở để đọc vào đích mở để viết, đóng nguồn, tiếp tục lặp - sử dụng withcâu lệnh để thực hiện việc đóng thay mặt bạn). Nếu chúng có các cột giống nhau, nhưng cũng có tiêu đề, bạn sẽ cần một readlinetệp trên mỗi tệp nguồn ngoại trừ tệp đầu tiên, sau khi bạn mở nó để đọc trước khi bạn sao chép nó vào đích, để bỏ qua dòng tiêu đề.

Nếu tất cả các tệp CSV không có cùng các cột thì bạn cần phải xác định xem bạn đang "hợp nhất" chúng theo nghĩa nào (như SQL JOIN? Hoặc "theo chiều ngang" nếu tất cả chúng có cùng số dòng? V.v., v.v. ) - thật khó để chúng tôi đoán ý bạn trong trường hợp đó.


Mỗi tệp có hai cột với tiêu đề. Tôi muốn hợp nhất chúng thành một tệp duy nhất có hai cột liên tiếp.
Chuck

3

Nếu CSV đã hợp nhất sẽ được sử dụng trong Python thì chỉ cần sử dụng globđể lấy danh sách các tệp cần chuyển đến fileinput.input()thông qua filesđối số, sau đó sử dụng csvmô-đun để đọc tất cả trong một lần.


3

Một thay đổi nhỏ đối với mã trên vì nó thực sự không hoạt động chính xác.

Nó sẽ như sau ...

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)

3

Khá dễ dàng để kết hợp tất cả các tệp trong một thư mục và hợp nhất chúng

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)

3

Nếu bạn đang làm việc trên linux / mac, bạn có thể làm điều này.

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


1

Bạn có thể nhập csv sau đó lặp qua tất cả các tệp CSV đang đọc chúng thành một danh sách. Sau đó, ghi lại danh sách ra đĩa.

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))

Phần trên không mạnh mẽ lắm vì nó không có xử lý lỗi cũng như không đóng bất kỳ tệp nào đang mở. Điều này sẽ hoạt động cho dù các tệp riêng lẻ có một hoặc nhiều hàng dữ liệu CSV trong đó hay không. Ngoài ra, tôi đã không chạy mã này, nhưng nó sẽ cung cấp cho bạn ý tưởng về những gì cần làm.


1

Thông qua giải pháp tạo ra @Adders và sau đó được cải tiến bởi @varun, tôi cũng đã thực hiện một số cải tiến nhỏ để lại toàn bộ CSV đã hợp nhất chỉ với tiêu đề chính:

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()

Trân trọng!!!


1

Bạn chỉ cần sử dụng csvthư viện tích hợp sẵn . Giải pháp này sẽ hoạt động ngay cả khi một số tệp CSV của bạn có tên cột hoặc tiêu đề hơi khác nhau, không giống như các câu trả lời được bình chọn nhiều nhất khác.

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)

Tệp hợp nhất sẽ chứa tất cả các cột có thể có ( header_keys) có thể được tìm thấy trong tệp. Bất kỳ cột nào vắng mặt trong tệp sẽ được hiển thị dưới dạng trống / trống (nhưng giữ nguyên phần dữ liệu còn lại của tệp).

Ghi chú:

  • Điều này sẽ không hoạt động nếu tệp CSV của bạn không có tiêu đề. Trong trường hợp đó, bạn vẫn có thể sử dụng csvthư viện, nhưng thay vì sử dụng DictReader& DictWriter, bạn sẽ phải làm việc với reader& writer.
  • Điều này có thể gặp sự cố khi bạn xử lý dữ liệu lớn vì toàn bộ nội dung đang được lưu trữ trong bộ nhớ ( merged_rowsdanh sách).

0

Tôi đã sửa đổi những gì @wisty nói là hoạt động với python 3.x, đối với những người bạn gặp vấn đề về mã hóa, tôi cũng sử dụng mô-đun os để tránh mã hóa khó

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()

0

Đây là một kịch bản:

  • Kết nối csv tập tin có tên SH1.csvđểSH200.csv
  • Giữ tiêu đề
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())

0

Đang cập nhật câu trả lời của wisty cho 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()

0

Giả sử bạn có 2 csvtệp như sau:

csv1.csv:

id,name
1,Armin
2,Sven

csv2.csv:

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

và bạn muốn kết quả như thế này csv3.csv:

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

Sau đó, bạn có thể sử dụng đoạn mã sau để làm điều đó:

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)

Với sự trợ giúp của vòng lặp, bạn có thể đạt được cùng một kết quả cho nhiều tệp như trong trường hợp của bạn (200 tệp csv).


0

Nếu các tệp không được đánh số theo thứ tự, hãy thực hiện cách tiếp cận đơn giản dưới đây: Python 3.6 trên máy 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)

0

Một chức năng dễ sử dụng:

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)

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()
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.