【问题标题】:How do I combine large csv files in python?如何在 python 中合并大型 csv 文件?
【发布时间】:2019-06-07 12:14:52
【问题描述】:

我有 18 个 csv 文件,每个大约 1.6Gb,每个包含大约 1200 万行。每个文件代表一年的数据。我需要合并所有这些文件,提取特定地理位置的数据,然后分析时间序列。最好的方法是什么?

我已经厌倦了使用 pd.read_csv 但我达到了内存限制。我尝试包含一个块大小参数,但这给了我一个 TextFileReader 对象,我不知道如何将它们组合起来制作一个数据框。我也尝试过 pd.concat 但这也不起作用。

【问题讨论】:

  • 需要和pandas一起吗?所有文件的 csv 数据格式是否相同?如果是,您可以考虑逐行读取/写入源/目标文件,避免内存问题。
  • 您可以尝试使用dask,因为它更适合管理内存中如此大的文件。
  • Reading a huge .csv file的可能重复
  • @martyn 它不需要和熊猫一起,但作为一个初学者我不知道我还能用什么。

标签: python pandas csv


【解决方案1】:

这是使用 pandas 组合非常大的 csv 文件的优雅方式。 该技术是每次迭代将行数(定义为 CHUNK_SIZE)加载到内存中,直到完成。这些行将以“附加”模式附加到输出文件。

import pandas as pd

CHUNK_SIZE = 50000
csv_file_list = ["file1.csv", "file2.csv", "file3.csv"]
output_file = "./result_merge/output.csv"

for csv_file_name in csv_file_list:
    chunk_container = pd.read_csv(csv_file_name, chunksize=CHUNK_SIZE)
    for chunk in chunk_container:
        chunk.to_csv(output_file, mode="a", index=False)

但是,如果您的文件包含标题,那么在接下来的文件中跳过标题是有意义的,除了第一个文件。由于重复标题是出乎意料的。在这种情况下,解决方案如下:

import pandas as pd

CHUNK_SIZE = 50000
csv_file_list = ["file1.csv", "file2.csv", "file3.csv"]
output_file = "./result_merge/output.csv"

first_one = True
for csv_file_name in csv_file_list:

    if not first_one: # if it is not the first csv file then skip the header row (row 0) of that file
        skip_row = [0]
    else:
        skip_row = []

    chunk_container = pd.read_csv(csv_file_name, chunksize=CHUNK_SIZE, skiprows = skip_row)
    for chunk in chunk_container:
        chunk.to_csv(output_file, mode="a", index=False)
    first_one = False

【讨论】:

  • 你应该将 header=False 添加到 to_csv(),否则每次你写一个块时都会写一个 header。就我而言,我的输入数据没有标题,因此 read_csv() 将第一行解释为标题,而 to_csv() 在写入每个块时插入了第一行。如果您需要输入文件的第一行,则将 header=None 添加到 read_csv()。
【解决方案2】:

内存限制已达到,因为您试图将整个 csv 加载到内存中。一个简单的解决方案是逐行读取文件(假设您的文件都具有相同的结构),控制它,然后将其写入目标文件:

filenames = ["file1.csv", "file2.csv", "file3.csv"]
sep = ";"

def check_data(data):
    # ... your tests
    return True # << True if data should be written into target file, else False

with open("/path/to/dir/result.csv", "a+") as targetfile:
    for filename in filenames :
        with open("/path/to/dir/"+filename, "r") as f:
            next(f) # << only if the first line contains headers
            for line in f:
                data = line.split(sep)
                if check_data(data):
                    targetfile.write(line)

更新check_data 方法的示例,跟随您的 cmets:

def check_data(data):
    return data[n] == 'USA' # < where n is the column holding the country

【讨论】:

  • 请注意,如果您的分隔符也出现在字段中,这将失败/行为怪异。在这种情况下,您可能需要对行数据进行更复杂的解析。
  • 那么这是否会创建我想要的数据的 csv 文件,然后我重新导入并从中进行分析?
  • 不,这将逐行读取您的所有 csv 文件,并且只有在通过 check_data 方法时才将每一行写入目标文件。 (使用此解决方案时没有损坏内存)
  • 因此,如果在 check_data 函数中,我只想为 18 个文件中的每一个文件的“国家”列中包含“美国”的行,这将如何编写?很抱歉这个简单的问题。
【解决方案3】:

您可以使用pd.DataFrame 转换TextFileReader 对象,如下所示:df = pd.DataFrame(chunk),其中chunk 的类型为TextFileReader。然后,您可以使用pd.concat 连接各个数据帧。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-31
    • 1970-01-01
    • 2020-09-03
    • 2019-03-27
    相关资源
    最近更新 更多