引用单个numpy数组元素
假设我有一个numpy数组,比如说:
x = np.arange(10)
那么有没有办法创建一个指向单个元素的引用,也就是说:
y = create_a_reference_to(x[3])
y = 100
print x
[ 0 1 2 100 4 5 6 7 8 9]
4 个回答
你可以在索引一个元素的时候使用 np.newaxis
,这样做的好处是,numpy会返回一个数组元素的引用,而不是一个普通的Python标量(简单的数值)。下面是一个最简单的示例。
>>> arr = np.asarray([0, 1, 2, 3])
>>> arr
array([0, 1, 2, 3])
>>> element2 = arr[2, np.newaxis]
>>> element2
array([2])
# Changing the element will modify the original array
>>> element2[:] = 100
>>> element2
array([100])
>>> arr
array([ 0, 1, 100, 3])
希望这对你有帮助。
补充说明 -- 根据jared的评论,None
也可以用来代替 np.newaxis
。
@goncalopp 提供了一个正确的答案,但还有一些其他方法也能达到类似的效果。
下面展示的所有写法都可以引用一个单独的元素,同时还能返回一个视图:
x = np.arange(10)
two_index_method = [None] * 10
scalar_element_method = [None] * 10
expansion_method = [None] * 10
for i in range(10):
two_index_method[i] = x[i:i+1]
scalar_element_method[i] = x[..., i] # x[i, ...] works, too
expansion_method[i] = x[:, np.newaxis][i] # np.newaxis == None
two_index_method[5] # Returns a length 1 numpy.ndarray, shape=(1,)
# >>> array([5])
scalar_element_method[5] # Returns a numpy scalar, shape = ()
# >>> array(5)
expansion_method[5] # Returns a length 1 numpy.ndarray, shape=(1,)
# >>> array([5])
x[5] = 42 # Change the value in the original `ndarray`
x
# >>> array([0, 1, 2, 3, 4, 42, 6, 7, 8, 9]) # The element has been updated
# All methods presented here are correspondingly updated:
two_index_method[5], scalar_element_method[5], expansion_method[5]
# >>> (array([42]), array(42), array([42]))
在 scalar_element_method
中,所指的对象是一个零维的标量,所以如果你试图通过 element[0]
来引用 ndarray
中的元素,会出现 IndexError
错误。对于一个标量 ndarray
,可以使用 element[()]
来引用其中的元素。这个方法也可以用来给长度为1的 ndarray
赋值,但有个不太好的副作用,就是它不会把长度为1的 ndarray
转换成 Python 的标量。幸运的是,有一个简单的方法 element.item()
,可以用来获取值,无论这个元素是长度为1的 ndarray
还是标量 ndarray
:
scalar_element_method[5][0] # This fails
# >>> IndexError: too many indices for array
scalar_element_method[5][()] # This works for scalar `ndarray`s
# >>> 42
scalar_element_method[5][()] = 6
expansion_method[5][0] # This works for length-1 `ndarray`s
# >>> 6
expansion_method[5][()] # Doesn't return a python scalar (or even a numpy scalar)
# >>> array([6])
expansion_method[5][()] = 8 # But can still be used to change the value by reference
scalar_element_method[5].item() # item() works to dereference all methods
# >>> 8
expansion_method[5].item()
# >>> [i]8
总结一下;你可以用 v = x[i:i+1]
、v = x[..., i]
或 v = x[:, None][i]
来创建一个单元素的视图 v
。虽然每种方法的设置和获取方式不同,但你总是可以用 v[()]=new_value
来赋值,并且可以用 v.item()
来获取 Python 的标量。
不,你不能这样做,这是故意设计的。
Numpy数组的类型是numpy.ndarray
。你可以用numpy.ndarray.item
来访问其中的单个元素,这个方法会“把数组中的一个元素复制到标准的Python标量(基本数据类型)并返回”。
我猜测Numpy之所以返回一个复制的值,而不是直接引用那个元素,是为了防止在Numpy的实现之外修改Numpy的元素。
想象一下,如果允许你直接引用单个元素,会发生什么呢?假设Numpy正在进行计算,而你在另一个线程中修改了某个元素,这样会有什么后果呢?
你不能直接创建一个指向单个元素的引用,但你可以对这个单个元素进行一个视图的操作:
>>> x = numpy.arange(10)
>>> y = x[3:4]
>>> y[0] = 100
>>> x
array([0, 1, 2, 100, 4, 5, 6, 7, 8, 9])
你不能这样做的原因是,Python 中的一切都是引用。当你写 y = 100
时,其实是修改了 y
指向的内容,而不是它的值。
如果你真的想要这种效果,可以通过使用属性来在实例属性上实现这个功能。注意,这只有在 Python 的数据模型中,定义了访问类属性时的额外操作的情况下才可能实现——对于变量来说,这种效果是无法实现的。