分块读取 Pandas 中的多个 CSV 文件

Posted

技术标签:

【中文标题】分块读取 Pandas 中的多个 CSV 文件【英文标题】:Read multiple CSV files in Pandas in chunks 【发布时间】:2019-07-26 00:39:46 【问题描述】:

当我们有多个 csv 文件并且所有 csv 的总大小约为 20gb 时,如何分块导入和读取多个 CSV?

我不想使用 Spark,因为我想在 SkLearn 中使用模型,所以我想要 Pandas 本身的解决方案。

我的代码是:

allFiles = glob.glob(os.path.join(path, "*.csv"))
df = pd.concat((pd.read_csv(f,sep=",") for f in allFiles))
df.reset_index(drop=True, inplace=True)

但这失败了,因为我路径中所有 csv 的总大小为 17gb。

我想分块阅读它,但如果我这样尝试会出现一些错误:

  allFiles = glob.glob(os.path.join(path, "*.csv"))
  df = pd.concat((pd.read_csv(f,sep=",",chunksize=10000) for f in allFiles))
  df.reset_index(drop=True, inplace=True)

我得到的错误是这样的:

“无法连接“”类型的对象;只有 pd.Series、pd.DataFrame 和 pd.Panel(已弃用)obj 有效”

有人可以帮忙吗?

【问题讨论】:

你试过df = pd.concat([pd.read_csv(f,sep=",",chunksize=10000) for f in allFiles])。 IE。带方括号?我认为普通的括号给你一个发电机...... @mortysporty no 没有帮助。同样的错误 查看pd.read_csv 的文档似乎指定chunksize 参数会使方法调用返回一个TextFileReader 对象(而不是数据框),该对象必须被迭代。跨度> 如果您没有必要的 RAM 来保存所有块的结果,那么无论您是否以块的形式读取它都无关紧要......您仍然要让您的机器去繁荣...... @JonClements - 我有内存。只是它使这个读取过程非常缓慢并降低了性能 【参考方案1】:

一种方法是使用 pd.read_csv(file, chunksize=chunksize) 对数据帧进行分块,然后如果您读取的最后一个块比块大小短,则保存额外的位,然后将其添加到第一个下一个块的文件。

但请确保读取下一个文件的较小的第一个块,使其等于总块大小。

def chunk_from_files(dir, master_chunksize):
    '''
    Provided a directory, loops through files and chunks out dataframes.
    :param dir: Directory to csv files.
    :param master_chunksize: Size of chunk to output.
    :return: Dataframes with master_chunksize chunk.
    '''
    files = os.listdir(dir)

    chunksize = master_chunksize
    extra_chunk = None # Initialize the extra chunk.
    for file in files:
        csv_file = os.path.join(dir, file)

        # Alter chunksize if extra chunk is not None.
        if extra_chunk is not None:
            chunksize = master_chunksize - extra_chunk.shape[0]

        for chunk in pd.read_csv(csv_file, chunksize=chunksize):
            if extra_chunk is not None: 
                # Concatenate last small chunk of previous file with altered first chunk of next file.
                chunk = pd.concat([chunk, extra_chunk])
                extra_chunk = None
                chunksize = master_chunksize # Reset chunksize.
            elif chunk.shape[0] < chunksize:
                # If last chunk is less than chunk size, set is as the extra bit.
                extra_chunk = chunk
                break

            yield chunk

【讨论】:

【参考方案2】:

这是一个有趣的问题。我没有尝试过,但我认为代码看起来像下面的脚本。

import pandas as pd
import csv
import glob
import os

#os.chdir("C:\\your_path\\")
results = pd.DataFrame([])
filelist = glob.glob("C:\\your_path\\*.csv")
#dfList=[]
for filename in filelist:
    print(filename)  
    namedf = pd.read_csv(filename, skiprows=0, index_col=0)
    results = results.append(namedf)

results.to_csv('C:\\your_path\\Combinefile.csv')


chunksize = 10 ** 6
for chunk in pd.read_csv('C:\\your_path\\Combinefile.csv', chunksize=chunksize):
    process(chunk)

也许您可以将所有内容加载到内存中并直接处理,但处理所有内容可能需要更长的时间。

【讨论】:

【参考方案3】:

要读取大型 csv 文件,您可以使用 chunksize,但在这种情况下,您必须像这样使用迭代器:

for df in pd.read_csv('file.csv', sep=',', iterator=True, chunksize=10000):
    process(df)

你必须连接或附加每个块

或者你可以这样做:

df = pd.read_csv('file.csv',, sep=',', iterator=True, chunksize=10000)
for chunk in df:
    process(chunk)

读取多个文件:例如

listfile = ['file1,'file2]
dfx = pd.DataFrame()
def process(d):
    #dfx=dfx.append(d) or dfx = pd.concat(dfx, d)
    #other coding

for f in listfile:
    for df in pd.read_csv(f, sep=',', iterator=True, chunksize=10000):
        process(df)

拥有大量文件后,您可以使用多处理库中的 DASK 或 Pool 来启动大量读取过程

不管怎样,要么你有足够的内存,要么你浪费时间

【讨论】:

如果我试图读取 1 个 csv,这可以正常工作。但在我的情况下,我的文件夹中有一堆 csv。所以 read_csv("file.csv") 在这里只使用 1 个文件但是我有一个包含很多 csv 文件的文件夹。这就是为什么在我的代码示例中连接它们 @pythonNinja 我建议您删除最多未用于机器学习的数据..我已经修改了我的程序以读取多个文件.. 谢谢,但是当我尝试连接数据时,我得到了同样的错误

以上是关于分块读取 Pandas 中的多个 CSV 文件的主要内容,如果未能解决你的问题,请参考以下文章

pandas read_csv读取大文件的Memory error问题

使用分块将 CSV 文件读入 Pandas 数据帧,生成单个目标数据帧

pandas分块读取大量数据集

pandas分块读取大量数据集

Pandas:使用循环和分层索引将多个 csv 文件导入数据帧

如何在使用 pandas.read_csv 读取 csv 文件时将 pandas.dataframe 中的元素转换为 np.float?