0

我希望对同一数据有两个不同的视图,其中行的顺序不同,这样通过一个视图所做的更改将反映在另一个视图中。具体如下代码

# Create original array
A = numpy.array([[0, 1, 2],
                 [3, 4, 5],
                 [6, 7, 8]])
B = A.view()[[0, 2, 1], :] # Permute the rows
print("(before) B =\n", B)

# Change a value in A
A[1, 2] = 143
print("(after) A =\n", A)
print("(after) B =\n", B)

具有以下输出:

(before) B =
 [[0 1 2]
  [6 7 8]
  [3 4 5]]
(after) A =
 [[  0   1   2]
  [  3   4 143]
  [  6   7   8]]
(after) B =
 [[0 1 2]
  [6 7 8]
  [3 4 5]]

但我希望最后一点是

(after) B =
 [[0   1   2]
  [6   7   8]
  [3   4 143]]

这个问题的答案表明,不可能在特定索引处查看视图,尽管该问题的 OP 正在询问数组的一个子集,而我想要整个数组的视图。(似乎这里的关键区别是切片与智能索引)

一篇询问按行切片、然后按列切片、按列切片、然后按行切片的帖子有一个公认的答案,即“重要的是您是按行切片还是按列切片......”。所以我尝试处理阵列的扁平视图..

A = numpy.array([[0, 1, 2],
                 [3, 4, 5],
                 [6, 7, 8]])
B = A.view()
B.shape = (A.size,)

A[1, 2] = 198
print("(After first) A =\n", A)
print("(After first) B =\n", B)

# Identity index map
all_idx = numpy.arange(A.size).reshape(A.shape)

# Swapped and flattened index map
new_row_idx = all_idx[[0, 2, 1]].flatten()

C = B[new_row_idx]

print("(Before second) C =\n", C)

# Manipulate through 'B'
B[7] = 666

print("(After second) B =\n", B)
print("(After second) C =\n", C)

给出以下输出:

(After first) A =
 [[  0   1   2]
 [  3   4 198]
 [  6   7   8]]
(After first) B =
 [  0   1   2   3   4 198   6   7   8]
(Before second) C =
 [  0   1   2   6   7   8   3   4 198]
(After second) B =
 [  0   1   2   3   4 198   6 666   8]
(After second) C =
 [  0   1   2   6   7   8   3   4 198]

如您所见,第 4 个条目C没有改变。我提到的第一篇文章的建议解决方案是创建一个副本,进行更改,然后更新原始数组。我可以编写函数来包装它,但这并不能消除我复制的次数。它所做的只是对用户隐藏它。

我在这里想念什么?我应该使用data这些数组的属性吗?如果是这样,了解如何做到这一点的一个好的起点是什么?

4

1 回答 1

2

数组具有shapestridesdtype1d data_buffer。Aview将有自己的shapestridesdtype和指向基数据缓冲区中某个位置的指针。slice仅使用这些属性就可以实现带 a 的索引。

但是无法以这种方式实现使用 [0,2,1] 之类的列表进行索引。所以numpy用自己的data_buffer创建一个新数组,a copy。[0,2,1] 索引列表/数组不与副本一起存储。

In [43]: A = np.arange(9).reshape(3,3)
In [44]: B = A[[0,2,1],:]
In [45]: A
Out[45]: 
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
In [46]: B
Out[46]: 
array([[0, 1, 2],
       [6, 7, 8],
       [3, 4, 5]])

ravel显示数据库中元素的顺序:

In [47]: A.ravel()
Out[47]: array([0, 1, 2, 3, 4, 5, 6, 7, 8])

元素的顺序B不同。

In [48]: B.ravel()
Out[48]: array([0, 1, 2, 6, 7, 8, 3, 4, 5])

相反,考虑使用切片重新排序的行:

In [49]: C = A[::-1,:]
In [50]: C
Out[50]: 
array([[6, 7, 8],
       [3, 4, 5],
       [0, 1, 2]])

In [52]: A.strides
Out[52]: (24, 8)

这是通过简单地改变来实现的strides

In [53]: C.strides
Out[53]: (-24, 8)

Transpose 也是一个视图,但步幅发生了变化:

In [54]: D = A.T
In [55]: D.strides
Out[55]: (8, 24)

我打算展示C.ravel(),但意识到 reshape 会复制(即使C是视图)。

最基本的一点是,任何numpy描述为的东西advanced indexing都会复制。对副本的更改不会出现在原始数组中。 https://numpy.org/doc/stable/reference/arrays.indexing.html#advanced-indexing

于 2021-01-07T08:08:16.493 回答