Numpy:对numpy.ndarray.view的永久性更改?

3 投票
1 回答
929 浏览
提问于 2025-04-17 04:37

如果我想永久性地改变一个numpy数组的数据类型,重新赋值是最好的方法吗?

这里有个例子来说明语法:

import numpy as np
x = np.array([1],dtype='float')
x = x.view(dtype=('x','float"))

不过,我更希望能“就地”改变数据类型。

有没有办法在不创建新数组的情况下直接改变数组的数据类型?还是说做类似这样的事情更好呢?:

x = x.view(dtype=('x',"float")).copy()

1 个回答

5

其实没有什么“永久”的数据类型。

Numpy数组基本上就是一种查看内存缓冲区的方法。

在numpy中,视图就是以不同的方式切割和处理同一个内存缓冲区,而不需要复制它。

不过要记住,这样做是让你对内存缓冲区的解释有更低级的控制。

举个例子:

import numpy as np
x = np.arange(10, dtype=np.int)

print 'An integer array:', x
print 'But if we view it as a float:', x.view(np.float)
print "...It's probably not what we expected..."

这样会得到:

An integer array: [0 1 2 3 4 5 6 7 8 9]
But if we view it as a float: [  0.00000000e+000   4.94065646e-324   
   9.88131292e-324   1.48219694e-323   1.97626258e-323   
   2.47032823e-323   2.96439388e-323   3.45845952e-323
   3.95252517e-323   4.44659081e-323]
...It's probably not what we expected...

所以,在这个例子中,我们把原始内存缓冲区的底层位解释成了浮点数。

如果我们想要制作一个新的副本,把整数转换成浮点数,可以用x.astype(np.float)

视图(数据类型的视图……切片也会返回一个视图,不过那是另一个话题)之所以有用,是因为你可以做一些很不错的操作,而不需要在内存中复制东西。

例如,如果你想要在原地将浮点数转换为整数(不复制内存),你可以用视图的一些技巧来实现这个目标。(基于@unutbu在这个问题上的回答

import numpy as np
x = np.arange(10, dtype=np.int)
print 'The original int array:', x

# We would have just used y = x.astype(np.float), but it makes a copy.
# This doesn't. If we're worried about memory consumption, it's handy!
y = x.view(np.float)
y[:] = x

print 'The new float array:', y
print 'But, the old int array has been modified in-place'
print x
print "They're both views into the same memory buffer!"

同样,你也可以进行各种低级的位操作:

import numpy as np
x = np.arange(10, dtype=np.uint16)
y = x.view(np.uint8)

print 'The original array:', x
print '...Viewed as uint8:', y
print '...Which we can do some tricks with', y[::2]

# Now let's interpret the uint16's as two streams of uint8's...
a, b = y[::2], y[1::2]
b[:] = np.arange(10, dtype=np.uint8)
print a
print b
print x
print y
# Notice that the original is modified... We're not duplicating memory anywhere!

至于你的问题,“更好”是相对的。你是想要一个副本,还是想以不同的方式查看同一个内存缓冲区呢?

顺便提一下,astype总是会创建一个副本,无论“输入”和“输出”的数据类型是什么。实际上,当人们提到view时,通常就是想要这个效果。(例如,如果你想在整数和浮点数之间转换,使用astype,而不是view,除非你需要精细管理内存使用。)

撰写回答