扩展到大型数据集#

pandas 提供了用于内存中分析的数据结构,这使得使用 pandas 分析大于内存的数据集变得有些棘手。就连占内存很大比例的数据集也会变得难以处理,因为一些 pandas 操作需要创建中间副本。

本文档提供了一些关于扩展你的分析到大型数据集的建议。它是 提升性能 的补充,后者侧重于加速适合内存的数据集的分析。

加载更少的数据#

假设我们在磁盘上的原始数据集有很多列。

要加载我们想要的列,我们有两种选择。选项 1 加载所有数据然后过滤到我们需要的部分。

选项 2 只加载我们请求的列。

如果我们衡量这两个调用的内存使用情况,我们会发现指定 columns 在此情况下使用的内存大约是 1/10。

使用 pandas.read_csv() ,你可以指定 usecols 来限制读取到内存中的列。并非所有 pandas 可以读取的文件格式都提供了读取列子集选项。

使用高效的数据类型#

默认的 pandas 数据类型不是内存效率最高的。这对于具有相对较少唯一值(通常称为“低基数”数据)的文本数据列尤其如此。通过使用更有效的数据类型,你可以将更大的数据集存储在内存中。

现在,让我们检查数据类型和内存使用情况,看看我们应该在哪里集中精力。

“name”列占用的内存比其他任何列都多。它只有几个唯一值,所以它是一个转换为 pandas.Categorical 的好选择。使用 pandas.Categorical ,我们将每个唯一的名称存储一次,并使用节省空间的整数来知道每行使用了哪个特定的名称。

我们可以进一步使用 pandas.to_numeric() 将数值列向下转换到它们的最小类型。

总而言之,我们将此数据集的内存占用量减少到了原始大小的 1/5。

有关 类别数据 的更多信息,请参阅 pandas.Categorical ,有关 pandas 所有 dtype 的概述,请参阅 dtypes

使用分块#

一些工作负载可以通过将一个大问题分解成许多小问题来实现分块。例如,将单个 CSV 文件转换为 Parquet 文件,并对目录中的每个文件重复此操作。只要每个块都适合内存,你就可以处理大于内存的数据集。

备注

分块适用于执行的操作需要块之间零个或最少协调的操作。对于更复杂的工作流,最好 using other libraries

假设我们在磁盘上有一个更大的“逻辑数据集”,它是一个 Parquet 文件目录。目录中的每个文件代表整个数据集的不同年份。

data
└── timeseries
    ├── ts-00.parquet
    ├── ts-01.parquet
    ├── ts-02.parquet
    ├── ts-03.parquet
    ├── ts-04.parquet
    ├── ts-05.parquet
    ├── ts-06.parquet
    ├── ts-07.parquet
    ├── ts-08.parquet
    ├── ts-09.parquet
    ├── ts-10.parquet
    └── ts-11.parquet

现在我们将实现一个“out-of-core”的 pandas.Series.value_counts() 。此工作流的峰值内存使用量是单个最大的块,加上一个存储到目前为止的唯一值计数的简短系列。只要单个文件适合内存,这适用于任意大小的数据集。

一些读取器,如 pandas.read_csv() ,提供了用于控制在读取单个文件时 chunksize 的参数。

手动分块对于不需要太复杂操作的工作流来说是一个不错的选择。一些操作,如 pandas.DataFrame.groupby() ,更难进行分块处理。在这些情况下,你最好切换到实现了这些“out-of-core”算法的另一个库。

使用其他库#

There are other libraries which provide similar APIs to pandas and work nicely with pandas DataFrame, and can give you the ability to scale your large dataset processing and analytics by parallel runtime, distributed memory, clustering, etc. You can find more information in the ecosystem page.