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

Ann*_*nne 106 python pandas

我一直想知道......如果我正在读取一个400MB的csv文件到一个pandas数据帧(使用read_csv或read_table),有没有办法猜测这需要多少内存?只是想更好地了解数据框架和内存......

小智 71

df.memory_usage() 将返回每列占用的数量:

>>> df.memory_usage()

Row_ID            20906600
Household_ID      20906600
Vehicle           20906600
Calendar_Year     20906600
Model_Year        20906600
...
Run Code Online (Sandbox Code Playgroud)

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

所以要获得整体内存消耗:

>>> df.memory_usage(index=True).sum()
731731000
Run Code Online (Sandbox Code Playgroud)

此外,传递memory_usage ='deep'将启用更准确的内存使用情况报告,该报告可以说明所包含对象的完整用法.

这是因为如果deep = False(默认情况),内存使用不包括不是数组组件的元素所占用的内存.

  • 你真的也想要`deep = True` (9认同)
  • 仅供参考,`memory_usage()`以字节为单位返回内存使用量(正如您所期望的那样). (6认同)
  • 为什么在有/没有deep = True之间存在如此巨大的差异? (2认同)

Bri*_*rns 62

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

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

sys.getsizeof(DF)

>>> import sys
>>> sys.getsizeof(df)
(gives results in bytes)
462456

df.memory_usage()

>>> df.memory_usage()
...
(lists each column at 8 bytes/row)

>>> df.memory_usage().sum()
71712
(roughly rows * cols * 8 bytes)

>>> df.memory_usage(deep=True)
(lists each column's full memory usage)

>>> df.memory_usage(deep=True).sum()
(gives results in bytes)
462432

df.info()

将数据帧信息打印到stdout.从技术上讲,这些是kibibytes(KiB),而不是千字节 - 正如文档字符串所说,"内存使用以人类可读的单位显示(基数为2的表示)." 因此,获取字节将乘以1024,例如451.6 KiB = 462,438字节.

>>> df.info()
...
memory usage: 70.0+ KB

>>> df.info(memory_usage='deep')
...
memory usage: 451.6 KB

  • 我使用`df.info(memory_usage =“ deep”)`,它返回“ 392.6 MB”,而`sys.getsizeof(df)`和`df.memory_usage(index = True,deep = True).sum()`两者都返回大约“ 411718016”(〜411MB)。您能否解释这3个结果为何不一致?谢谢 (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` 将 *byte* 转换为 *MB*,这让我很困惑. 无论如何,感谢您的帮助:D。 (2认同)

fir*_*ynx 32

我想我会为讨论带来更多数据.

我对这个问题进行了一系列测试.

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

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

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

在第一个实验中,我在我的数据集中只使用了浮点数.

这是与csv文件相比内存增加的方式,作为行数的函数.(大小以兆字节为单位)

内存和CSV大小(以兆字节为单位)与具有float条目的行数的函数关系

第二个实验我有相同的方法,但数据集中的数据只包含短字符串.

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

似乎csv的大小与数据帧的大小之间的关系可以变化很大,但是内存中的大小总是会大2-3倍(对于本实验中的帧大小)

我希望通过更多实验来完成这个答案,如果你想让我尝试一些特别的东西,请评论.

  • 你的y轴是多少? (3认同)

Jef*_*eff 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
Run Code Online (Sandbox Code Playgroud)

技术上内存就是这个(包括索引)

In [16]: df.values.nbytes + df.index.nbytes + df.columns.nbytes
Out[16]: 168000160
Run Code Online (Sandbox Code Playgroud)

因此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
Run Code Online (Sandbox Code Playgroud)

当写为二进制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
Run Code Online (Sandbox Code Playgroud)

数据是随机的,因此压缩无助于此


Phi*_*oud 10

如果您知道dtype数组的s,那么您可以直接计算存储数据所需的字节数+一些Python对象本身的字节数.numpy数组的一个有用属性是nbytes.您可以DataFrame通过执行来从大熊猫中的数组中获取字节数

nbytes = sum(block.values.nbytes for block in df.blocks.values())
Run Code Online (Sandbox Code Playgroud)

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

编辑:

有关详细信息,请参阅numpy标量类型页面object dtype.由于只存储了引用,因此您还需要考虑数组中对象的大小.正如该页面所说,对象数组有点类似于Python list对象.

  • 是的,对于任何对象类型,您都需要一个 8 字节指针 + 大小(对象) (2认同)

Vik*_*kez 8

就在这里.Pandas会将您的数据存储在二维numpy ndarray结构中,通过dtypes对它们进行分组.ndarray基本上是一个带有小标题的原始C数据数组.所以你可以通过将dtype它包含的大小乘以数组的大小来估计它的大小.

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

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


Zah*_*eez 6

我相信这给了python中任何对象的内存大小.内部需要检查大熊猫和numpy

>>> import sys
#assuming the dataframe to be df 
>>> sys.getsizeof(df) 
59542497
Run Code Online (Sandbox Code Playgroud)


Ler*_*ang 5

要打印人类可读的结果,您可以尝试以下操作:

suffixes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
def humansize(nbytes):
    i = 0
    while nbytes >= 1024 and i < len(suffixes)-1:
        nbytes /= 1024.
        i += 1
    f = ('%.2f' % nbytes).rstrip('0').rstrip('.')
    return '%s %s' % (f, suffixes[i])

df.memory_usage(index=True, deep=True).apply(humansize)
# Index  128 B
# a      571.72 MB
# b      687.78 MB
# c      521.6 MB
# dtype: object

humansize(df.memory_usage(index=True, deep=True).sum())
# 1.74 GB
Run Code Online (Sandbox Code Playgroud)

代码改编自此答案。