簡體   English   中英

按python中列的值拆分大csv文件

[英]Split big csv file by the value of a column in python

我有一個csv大文件,我無法在內存中使用python處理。 在使用以下邏輯對特定列的值進行分組后,我將其拆分為多個塊:

def splitDataFile(self, data_file):

    self.list_of_chunk_names = []
    csv_reader = csv.reader(open(data_file, "rb"), delimiter="|")
    columns = csv_reader.next()

    for key,rows in groupby(csv_reader, lambda row: (row[1])):
        file_name = "data_chunk"+str(key)+".csv"
        self.list_of_chunk_names.append(file_name)

        with open(file_name, "w") as output:
            output.write("|".join(columns)+"\n")
            for row in rows:
                output.write("|".join(row)+"\n")

    print "message: list of chunks ", self.list_of_chunk_names

    return

邏輯正在運行,但速度很慢。 我想知道如何優化這個? 比如熊貓?

編輯

進一步的解釋:我不是在尋找一個簡單的分割到相同大小的塊(比如每個有1000行),我想用列的值進行拆分,這就是我使用groupby的原因。

使用這個Python 3程序:

 #!/usr/bin/env python3
 import binascii
 import csv
 import os.path
 import sys
 from tkinter.filedialog import askopenfilename, askdirectory
 from tkinter.simpledialog import askinteger

 def split_csv_file(f, dst_dir, keyfunc):
     csv_reader = csv.reader(f)
     csv_writers = {}
     for row in csv_reader:
         k = keyfunc(row)
         if k not in csv_writers:
             csv_writers[k] = csv.writer(open(os.path.join(dst_dir, k),
                                              mode='w', newline=''))
         csv_writers[k].writerow(row)

 def get_args_from_cli():
     input_filename = sys.argv[1]
     column = int(sys.argv[2])
     dst_dir = sys.argv[3]
     return (input_filename, column, dst_dir)

 def get_args_from_gui():
     input_filename = askopenfilename(
         filetypes=(('CSV', '.csv'),),
         title='Select CSV Input File')
     column = askinteger('Choose Table Column', 'Table column')
     dst_dir = askdirectory(title='Select Destination Directory')
     return (input_filename, column, dst_dir)

 if __name__ == '__main__':
     if len(sys.argv) == 1:
         input_filename, column, dst_dir = get_args_from_gui()
     elif len(sys.argv) == 4:
         input_filename, column, dst_dir = get_args_from_cli()
     else:
         raise Exception("Invalid number of arguments")
     with open(input_filename, mode='r', newline='') as f:
         split_csv_file(f, dst_dir, lambda r: r[column-1]+'.csv')
         # if the column has funky values resulting in invalid filenames
         # replace the line from above with:
         # split_csv_file(f, dst_dir, lambda r: binascii.b2a_hex(r[column-1].encode('utf-8')).decode('utf-8')+'.csv')

將其保存為split-csv.py並從資源管理器或命令行運行它。

例如,基於第1列拆分superuser.csv並在dstdir下編寫輸出文件使用:

 python split-csv.py data.csv 1 dstdir

如果不帶參數運行它,基於Tkinter的GUI將提示您選擇輸入文件,列(基於1的索引)和目標目錄。

REF

我將使用類似下面的內容,我將迭代要拆分的列的唯一值,以過濾數據塊。

def splitWithPandas(data_file, split_by_column):
        values_to_split_by = pd.read_csv(data_file, delimiter="|", usecols=[split_by_column])
        values_to_split_by.drop_duplicates()
        values_to_split_by = pd.unique(values_to_split_by.values.ravel())

        for i in values_to_split_by:
            iter_csv = pd.read_csv(data_file, delimiter="|", chunksize=100000)
            df = pd.concat([chunk[chunk[split_by_column] == i] for chunk in iter_csv])
            df.to_csv("data_chunk_"+i, sep="|", index=False)

通過使用pandas的內置分塊功能( chunksize關鍵字arg to read_csv ),您可能會獲得最佳性能,

http://pandas.pydata.org/pandas-docs/version/0.16.2/generated/pandas.read_csv.html

例如,

reader = pd.read_table('my_data.csv', chunksize=4)
for chunk in reader:
  print(chunk)

編輯:

這可能會讓你到處

import pandas as pd

group_col_indx = 1
group_col = pd.read_csv('test.csv', usecols=[group_col_indx])
keys = group_col.iloc[:,0].unique()

for key in keys:
    df_list = []
    reader = pd.read_csv('test.csv', chunksize=2)
    for chunk in reader:
        good_rows = chunk[chunk.iloc[:,group_col_indx] == key]
        df_list.append(good_rows)
    df_key = pd.concat(df_list)

懷疑每次處理新的行塊時,最大的瓶頸是打開和關閉文件句柄。 只要您寫入的文件數量不是太大,更好的方法是保持所有文件都打開。 這是一個大綱:

def splitDataFile(self, data_file):
    open_files = dict()
    input_file = open(data_file, "rb")
    try:
        ...
        csv_reader = csv.reader(input_file, ...)
        ...
        for key, rows in groupby(csv_reader, lambda row: (row[1])):
            ...
            try:
                output = open_files[key]
            except KeyError:
                output = open(file_name, "w")
            output.write(...)
            ...
    finally:
        for open_file in open_files.itervalues():
            open_file.close()
        input_file.close()

當然,如果您只有一個組具有任何給定的密鑰,這將無濟於事。 (實際上它可能會讓事情變得更糟,因為你最終會不必要地打開一堆文件。)你越頻繁地寫一個文件,你就會從這個變化中獲得更多的好處。

如果需要,可以將它與pandas結合使用,並使用read_csvread_table的分塊功能來處理輸入處理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM