首页 > 解决方案 > NumPy 的字符串数组的内存使用量远大于对象数组

问题描述

我还是 Numpy 的新手,并且正在搞乱 Numpy 的dtypes,发现特定于字符串的 dtype,也就是 'U',比对象类型占用更多的内存空间。说明这一事实的代码如下:

size= 100000
half_size = size//2

ind1 = np.arange(half_size)*2+1
ind2 = np.arange(half_size)*2

X = np.empty(size, dtype = 'object')

X[ind1] = 'smile'
X[ind2] = 'smile2'

W = np.empty(size, dtype = 'U6')
W[ind1] = 'smile'
W[ind2] = 'smile2'

print(X.nbytes)
print(W.nbytes)

结果如下:

800000
2400000

我的问题如下:

1)为什么会发生这种情况?为什么 dtype = 'U6' 占用的内存是 dtype = object 的 3 倍

2) 有没有办法创建一个比 dtype = object 占用更少内存空间的字符串 numpy 数组?

先感谢您

编辑:我想解释一下我的帖子不是另一篇帖子的重复,因为我的帖子是关于内存使用的,而另一篇帖子没有提到任何关于 dtype = 'U' vs dtype = 'object 的内存使用情况'

EDIT2:虽然我已经从另一篇文章中学到了一些新东西,但不幸的是,另一篇文章没有回答我的问题,因为我的文章是关于内存使用的,而另一篇文章没有提到关于 dtype = 'U' vs 的内存使用的任何内容dtype = '对象'

标签: pythonarraysstringnumpymemory

解决方案


sys.getsizeof是检查内存使用情况的一种方法,尽管您必须明智地使用它,了解它到底在测量什么。对于数组,它工作得相当好。

没有任何元素的数组:

In [28]: sys.getsizeof(np.array([],'U6'))                                                            
Out[28]: 96
In [29]: sys.getsizeof(np.array(['smile','smile1'],'U6'))                                            
Out[29]: 144
In [30]: sys.getsizeof(np.array(['smile','smile1'],'S6'))                                            
Out[30]: 108

使用 2 个“U6”字符串,大小跳跃 48,4 个字节/字符 *2 个元素 *6 个字符/元素

使用 bytestring dtype(Py2 的默认值),跳转为 12、2*6。

bytestring 更紧凑,但请注意显示:

In [31]: np.array(['smile','smile1'],'S6')                                                           
Out[31]: array([b'smile', b'smile1'], dtype='|S6')

对于对象 dtype:

In [32]: sys.getsizeof(np.array(['smile','smile1'],object))                                          
Out[32]: 112

那是 16 个字节 - 2*8

但是加上 Python 字符串的大小,额外的 133 个字节

In [33]: sys.getsizeof('smile')                                                                      
Out[33]: 78
In [34]: sys.getsizeof('smile1')                                                                     
Out[34]: 55

对于字节环:

In [36]: sys.getsizeof(b'smile')                                                                     
Out[36]: 38
In [37]: sys.getsizeof(b'smile1')                                                                    
Out[37]: 39

请注意,当我添加一个字节字符时,大小会增加 1。但是当我添加一个 unicode 字符时,大小实际上会减小。unicode 字符串的大小更难预测。我认为它最多可以为每个字符分配 4 个字节,但实际数量取决于字符和编码。通常我们不会尝试对 Python 的字符串处理进行微管理。(除此之外,我相信 Python 有某种字符串缓存。)

但是当你分配

X[ind1] = 'smile'
X[ind2] = 'smile2'

在对象情况下,您创建两个 Python 字符串,并将引用(指针)分配给数组。所以内存使用量是数组(1000...*8 字节)加上这 2 个字符串的 133 字节。

在 'U6' 的情况下,每个元素占用 4*6 字节,无论它是 'smile' 还是 'smile1'(或 's')。数组的每个元素都使用相同的空间,无论是否需要所有元素来表示字符串。

一般来说,弦乐不是一种numpy力量。当字符串具有相似的大小时,'U' 或 'S' dtype 的内存使用是可以的,但如果字符串的长度不同、重复和/或是 unicode,则不太理想。 numpy不做太多自己的字符串处理。这些np.char函数只是 Python 字符串方法的薄包装。

pandas已选择使用objectdtype 而不是字符串 dtypes。


推荐阅读