Python 创建numpy数组的置换浅拷贝

Python 创建numpy数组的置换浅拷贝,python,numpy,numpy-slicing,numpy-indexing,Python,Numpy,Numpy Slicing,Numpy Indexing,我希望对同一数据有两个不同的视图,行的顺序不同,这样通过一个视图所做的更改将反映在另一个视图中。具体来说,下面的代码 # 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)

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

# 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 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]
但我希望最后一点是

(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)
这将提供以下输出:

(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 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]
如您所见,
C
的第4个条目未被更改。建议的解决方案是创建副本,进行更改,然后更新原始阵列。我可以编写函数来包装它,但这并不能减少复制的次数。它所做的只是对用户隐藏它


我错过了什么?我应该使用这些数组的
data
属性吗?如果是这样的话,了解如何实现这一点的好起点是什么?

阵列具有
形状
跨步
数据类型
和1d数据缓冲区。
视图
将有自己的
形状
步幅
数据类型
,以及指向数据库数据缓冲区中某个位置的指针。使用
切片
进行索引可以仅使用这些属性来实现

但是,使用[0,2,1]这样的列表进行索引无法通过这种方式实现。因此,
numpy
创建了一个新的数组,它有自己的数据缓冲区,
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)
这只需更改
步幅即可实现:

In [53]: C.strides
Out[53]: (-24, 8)
转置也是一种视图,具有变化的步幅:

In [54]: D = A.T
In [55]: D.strides
Out[55]: (8, 24)
我本来打算展示
C.ravel()
,但我意识到重塑可以复制(即使
C
是一个视图)


基本要点是,任何
numpy
描述为
advanced index
的内容都将复制。对副本的更改将不会显示在原始阵列中

一个数组有
形状
跨步
数据类型
和1d数据缓冲区。
视图
将有自己的
形状
步幅
数据类型
,以及指向数据库数据缓冲区中某个位置的指针。使用
切片
进行索引可以仅使用这些属性来实现

但是,使用[0,2,1]这样的列表进行索引无法通过这种方式实现。因此,
numpy
创建了一个新的数组,它有自己的数据缓冲区,
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)
这只需更改
步幅即可实现:

In [53]: C.strides
Out[53]: (-24, 8)
转置也是一种视图,具有变化的步幅:

In [54]: D = A.T
In [55]: D.strides
Out[55]: (8, 24)
我本来打算展示
C.ravel()
,但我意识到重塑可以复制(即使
C
是一个视图)


基本要点是,任何
numpy
描述为
advanced index
的内容都将复制。对副本的更改将不会显示在原始阵列中

注意第二个链接中的Zwinck答案。它狭隘地解决了OP问题,不应被视为一般性的解释。阅读评论。根本没有办法做到这一点,至少从狭隘的角度来看,这个问题是有框架的。Numpy处理连续的内存块;有一些变通方法,但数据的任意排列总是会破坏连续性。其实很简单……但是,如果您的基本目标是以置换方式写入数组,那么您可以非常轻松地完成这项工作,这比问题底部的代码要简单得多。(也就是说,除非我误解了您的目标。)但这与您所问的问题完全不同。您希望对置换数组执行什么类型的操作?像这样简单的一个接一个的任务,还是更复杂的任务?我的目标是支持不同库使用的不同节点ID编号方案,这些库支持有限元网格上的操作。节点坐标集不会更改,但分配给它们的全局ID不同。我希望在不复制网格数据的情况下执行此操作,因为在某些情况下,网格数据可能相当大。请小心第二个链接中的Zwinck答案。它狭隘地解决了OP问题,不应被视为一般性的解释。阅读评论。根本没有办法做到这一点,至少从狭隘的角度来看,这个问题是有框架的。Numpy处理连续的内存块;有一些变通方法,但数据的任意排列总是会破坏连续性。其实很简单……但是,如果您的基本目标是以置换方式写入数组,那么您可以非常轻松地完成这项工作,这比问题底部的代码要简单得多。(也就是说,除非我误解了您的目标。)但这与您所问的问题完全不同。您希望对置换数组执行什么类型的操作?像这样简单的一个接一个的任务,还是更复杂的任务?我的目标是支持不同库使用的不同节点ID编号方案,这些库支持对有限元的操作