我一直在想... ... 如果我正在将一个400MB 的 csv 文件读入熊猫数据框(使用 read _ csv 或 read _ table) ,有没有办法估计这将需要多少内存?只是想更好地感受一下数据帧和内存。
有的。熊猫将存储您的数据在二维麻木的 ndarray结构分组他们的 dtype。ndarray基本上是一个带有小头的原始 C 数组。因此,您可以通过将它包含的 dtype的大小与数组的维数相乘来估计它的大小。
ndarray
dtype
例如: 如果有1000行,其中有2个 np.int32和5个 np.float64列,那么 DataFrame 将有一个2x1000 np.int32数组和一个5x1000 np.float64数组,即:
np.int32
np.float64
4字节 * 2 * 1000 + 8字节 * 5 * 1000 = 48000字节
如果您知道数组的 dtype,那么您可以直接计算存储数据所需的字节数 + Python 对象本身所需的一些字节数。numpy数组的一个有用属性是 nbytes。通过执行以下操作,您可以从熊猫 DataFrame中的数组中获得字节数
numpy
nbytes
DataFrame
nbytes = sum(block.values.nbytes for block in df.blocks.values())
object dtype 数组每个对象存储8个字节(object dtype 数组存储一个指向不透明的 PyObject的指针) ,所以如果你的 csv 中有字符串,你需要考虑到 read_csv会把它们转换成 object dtype 数组,并相应地调整你的计算。
object
PyObject
read_csv
编辑:
有关 object dtype的详细信息,请参阅 标量类型页。由于只存储引用,因此还需要考虑数组中对象的大小。正如该页所说,对象数组在某种程度上类似于 Pythonlist对象。
list
你得反着来。
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
因此,168 MB 的内存和400 MB 的文件,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
数据是随机的,所以压缩没有太大帮助
我想我应该给讨论带来更多的数据。
我对这个问题进行了一系列测试。
通过使用 pythonresource包,我得到了进程的内存使用情况。
resource
通过将 csv 写入 StringIO缓冲区,我可以很容易地以字节为单位测量它的大小。
StringIO
我做了两个实验,每个实验都创建了20个数据框架,它们的大小在10,000行到1000,000行之间不断增加。都有10列。
在第一个实验中,我只在数据集中使用浮点数。
与 csv 文件相比,内存是如何随行数的增加而增加的。(以兆字节为单位)
第二个实验我也采用了同样的方法,但是数据集中的数据仅由短串组成。
看起来 csv 的大小和数据帧的大小之间的关系可能有很大的不同,但是内存中的大小总是要大2-3倍(对于这个实验中的帧大小)
我想用更多的实验来完成这个答案,如果你想让我尝试一些特别的东西,请评论。
df.memory_usage() 将返回每列占用的字节数:
df.memory_usage()
>>> df.memory_usage() Row_ID 20906600 Household_ID 20906600 Vehicle 20906600 Calendar_Year 20906600 Model_Year 20906600 ...
若要包含索引,请传递 index=True。
index=True
为了得到总体内存消耗:
>>> df.memory_usage(index=True).sum() 731731000
此外,传递 deep=True将启用更准确的内存使用情况报告,该报告说明了所包含对象的全部使用情况。
deep=True
这是因为如果 deep=False(默认情况) ,内存使用量不包括不是数组组件的元素所消耗的内存。
deep=False
我相信这给了 Python 中任何对象的内存大小。熊猫和麻木的内脏需要检查
>>> import sys #assuming the dataframe to be df >>> sys.getsizeof(df) 59542497
下面是不同方法的比较—— sys.getsizeof(df)是最简单的。
sys.getsizeof(df)
对于这个例子,df是一个数据框架,包含814行,11列(2整数,9个对象)——从427kb 的 shapefile 中读取
df
>>> import sys >>> sys.getsizeof(df) (gives results in bytes) 462456
>>> 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
将数据帧信息打印到标准输出。从技术上讲,它们是 kibibyte (KiB) ,而不是 Kobytes ——正如 docstring 所说,“内存使用量以人类可读的单位(基数为2的表示)显示。”因此,要获取字节,需要乘以1024,例如,451.6 KiB = 462,438字节。
>>> df.info() ... memory usage: 70.0+ KB >>> df.info(memory_usage='deep') ... memory usage: 451.6 KB
要打印人类可读的结果,您可以尝试这样做:
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
代码改编自 这个和 这个答案。