引用单个numpy数组元素

9 投票
4 回答
5834 浏览
提问于 2025-04-18 06:31

假设我有一个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 个回答

0

你可以在索引一个元素的时候使用 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

0

@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 的标量。

2

不,你不能这样做,这是故意设计的

Numpy数组的类型是numpy.ndarray。你可以用numpy.ndarray.item来访问其中的单个元素,这个方法会“把数组中的一个元素复制到标准的Python标量(基本数据类型)并返回”。

我猜测Numpy之所以返回一个复制的值,而不是直接引用那个元素,是为了防止在Numpy的实现之外修改Numpy的元素

想象一下,如果允许你直接引用单个元素,会发生什么呢?假设Numpy正在进行计算,而你在另一个线程中修改了某个元素,这样会有什么后果呢?

12

你不能直接创建一个指向单个元素的引用,但你可以对这个单个元素进行一个视图的操作:

>>> 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 的数据模型中,定义了访问类属性时的额外操作的情况下才可能实现——对于变量来说,这种效果是无法实现的

撰写回答