如何估算熊猫的DataFrame需要多少内存?


125

我一直在想...如果我正在将400MB的csv文件读入熊猫数据帧(使用read_csv或read_table),是否有任何方法可以估算出这将需要多少内存?只是试图更好地了解数据帧和内存...


您始终可以查看该过程及其单个文件的内存使用情况。如果您正在运行linux,请尝试top然后Shift + M对我的内存使用情况进行排序。
JayQuerie.com 2013年

我觉得我应该为这个公开的熊猫问题做广告。
安迪·海登

3
我有一个具有400万行的大型数据框。我发现其空子集x=df.loc[[]]需要0.1几秒钟来进行计算(以提取零行),并且还需要数百兆字节的内存,就像原始数据帧一样,这可能是由于其下的某些复制。
osa

熊猫首席开发人员针对旧帖子的新链接
Saladi

Answers:


97

df.memory_usage() 将返回每列占用多少:

>>> df.memory_usage()

Row_ID            20906600
Household_ID      20906600
Vehicle           20906600
Calendar_Year     20906600
Model_Year        20906600
...

要包含索引,请传递index=True

因此,要获得整体内存消耗:

>>> df.memory_usage(index=True).sum()
731731000

此外,传递deep=True将启用更准确的内存使用情况报告,该报告说明了所包含对象的全部使用情况。

这是因为内存使用量不包括非数组元素if占用的内存deep=False(默认情况下)。


1
所有列的内存使用量之和真的对内存使用量有影响吗?我可以想象会有更多的开销。
firelynx

14
您真的也想要deep=True
smci

df.memory_usage()的总和不等于sys.getsizeof(df)!有很多开销。正如smci所提到的,您需要deep=True
vagabond

11
仅供参考,memory_usage()以字节为单位返回内存使用情况(如您所愿)。
engelen

2
为什么有/没有deep = True之间有如此巨大的区别?
Nguai al

83

这是不同方法的比较- sys.getsizeof(df)最简单。

对于此示例,df是一个具有814行,11列(2个整数,9个对象)的数据帧-从427kb shapefile中读取

sys.getsizeof(df)

>>>导入系统
>>> sys.getsizeof(df)
(给出的结果以字节为单位)
462456

df.memory_usage()

>>> df.memory_usage()
...
(以8字节/行列出每一列)

>>> df.memory_usage()。sum()
71712
(大约行*列* 8字节)

>>> df.memory_usage(deep = True)
(列出每列的全部内存使用情况)

>>> df.memory_usage(deep = True).sum()
(给出的结果以字节为单位)
462432

df.info()

将数据框信息打印到标准输出。从技术上讲,它们是千字节(KiB),而不是千字节-正如文档字符串所说,“内存使用情况以人类可读的单位(以2为基数的表示形式)显示”。因此,要获取字节将乘以1024,例如451.6 KiB = 462,438字节。

>>> df.info()
...
内存使用量:70.0+ KB

>>> df.info(memory_usage ='deep')
...
内存使用量:451.6 KB

g 上面的代码指的是什么对象或模块?
zozo

@zozo woops-是一个错字-已修复
Brian Burns

2
我用df.info(memory_usage="deep"),则返回“392.6 MB”,而sys.getsizeof(df)df.memory_usage(index=True, deep=True).sum()这两个回报约“411718016”(〜411MB)。您能否解释这三个结果为何不一致?谢谢
Catbuilts 18-10-29

2
@BrianBurns:df.memory_usage(deep=True).sum()返回与几乎相同df.memory_usage(index=True, deep=True).sum()。就我而言,index不需要太多内存。有趣的是,我发现411718016/1024/1024 = 392.6,因此 df.info(memory_usage="deep")可能2^10会将字节转换为MB,这使我感到困惑。无论如何,谢谢您的帮助:D。
Catbuilts '18 -10-30

1
@Catbuilts啊,这解释了!df.info返回兆字节(2 ^ 10),而不是兆字节(10 ^ 6)-将修改答案。
布赖恩·伯恩斯

43

我想我可以带一些更多的数据来讨论。

我对此问题进行了一系列测试。

通过使用python resource包,我得到了进程的内存使用情况。

通过将csv写入StringIO缓冲区,我可以轻松地以字节为单位测量它的大小。

我进行了两个实验,每个实验创建20个数据框,这些数据框的大小在10,000行和1,000,000行之间递增。两者都有10列。

在第一个实验中,我仅在数据集中使用浮点数。

与csv文件相比,这是内存随行数变化的方式。(以兆字节为单位)

内存和CSV大小(以兆字节为单位)是带浮点输入的行数的函数

第二个实验我采用了相同的方法,但是数据集中的数据仅包含短字符串。

内存和CSV大小(以兆字节为单位)是带字符串条目的行数的函数

似乎csv的大小与数据帧的大小之间的关系可以相差很多,但是内存中的大小将始终以2-3的倍数增大(对于本实验中的帧大小)

我希望通过更多实验来完成此答案,如果您想让我尝试一些特别的事情,请发表评论。


您的y轴是多少?
伊利亚·舒罗夫

1
磁盘上的max_rss和csv大小(以兆字节为单位)
firelynx

31

您必须反向执行此操作。

In [4]: DataFrame(randn(1000000,20)).to_csv('test.csv')

In [5]: !ls -ltr test.csv
-rw-rw-r-- 1 users 399508276 Aug  6 16:55 test.csv

从技术上讲,内存与此有关(包括索引)

In [16]: df.values.nbytes + df.index.nbytes + df.columns.nbytes
Out[16]: 168000160

内存为168MB,文件大小为400MB,1M行包含20个浮点数

DataFrame(randn(1000000,20)).to_hdf('test.h5','df')

!ls -ltr test.h5
-rw-rw-r-- 1 users 168073944 Aug  6 16:57 test.h5

作为二进制HDF5文件写入时,更加紧凑

In [12]: DataFrame(randn(1000000,20)).to_hdf('test.h5','df',complevel=9,complib='blosc')

In [13]: !ls -ltr test.h5
-rw-rw-r-- 1 users 154727012 Aug  6 16:58 test.h5

数据是随机的,因此压缩没有太大帮助


那太聪明了!任何想法如何测量您需要使用读取文件的内存read_csv
安迪·海登

不知道如何衡量阅读的内容;IIRC的大小可能是保存数据所需的最终内存的2倍(来自wes的文章),但我认为他将其降低为一个常数+最终内存
Jeff

嗯,我需要重新阅读,我记得2x是某种算法的一些方便的理论最小值,即使这还不算很酷。
安迪·海登

您可以使用iotoplike top/ htop来(实时)观察IO性能。
菲利普·

1
nbytes如果您在数据帧中有例如字符串,这将是一个严重的低估。
osa 2015年

10

如果知道dtype数组的,则可以直接计算存储数据所需的字节数+ Python对象本身的字节数。numpy数组的有用属性是nbytes。您可以DataFrame通过执行以下操作从熊猫数组中获取字节数

nbytes = sum(block.values.nbytes for block in df.blocks.values())

objectdtype数组为每个对象存储8个字节(对象dtype数组存储指向opaque的指针PyObject),因此如果csv中有字符串,则需要考虑read_csv将这些字符串转换为objectdtype数组并相应地调整计算的情况。

编辑:

有关的更多详细信息,请参见numpy标量类型页面object dtype。由于仅存储一个引用,因此您还需要考虑数组中对象的大小。如该页面所述,对象数组在某种程度上类似于Python list对象。


谢谢菲利普!只是要澄清-对于字符串,我们需要8个字节用于指向字符串对象的指针,再加上实际的字符串对象?
安妮

1
是的,对于任何对象类型,您都需要一个8字节的指针+ size(object)
Viktor Kerkez,2013年

1
建议df.blocks.values()看起来df.blocks现在是字典
MRocklin

8

就在这里。熊猫会将您的数据存储在二维numpy ndarray结构中,并按dtypes将其分组。ndarray基本上是带有小标头的原始C数据数组。因此,您可以通过将dtype其包含的大小乘以数组的大小来估算其大小。

例如:如果您有1000行2 列np.int32和5 np.float64列,则DataFrame将具有np.int32一个2x1000 np.float64数组和一个5x1000 数组,即:

4bytes * 2 * 1000 + 8bytes * 5 * 1000 = 48000字节


@AndyHayden您的建设成本是什么?一个实例的大小DataFrame
菲利普·乌云

感谢维克多!@Andy-知道建筑成本多少吗?
安妮

它不包括在内,但是在Cython中pandas有一个非常有效的实现read_table(比numpy的loadtxt更好),因此我假设它解析器并将数据直接存储到ndarray
维克多·柯基兹

@PhillipCloud,您必须构建它,这会占用内存。.我似乎还记得所提到的两倍大小?...
Andy Hayden

6

我相信这可以为python中的任何对象提供内存中的大小。需要检查熊猫和numpy的内部

>>> import sys
#assuming the dataframe to be df 
>>> sys.getsizeof(df) 
59542497
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.