编辑:我发现问题归结为:
如果你运行这段代码:
A = ones((10,4))
view = A[:,1]
view.fill(7)
A
或
A = ones((10,4))
view = A[:,1:3]
view.fill(7)
A
你会看到 A 的列发生了变化
如果你运行这个:
A = ones((10,4))
view = A[:,(1,2)]
view.fill(7)
A
A 没有副作用。这种行为是故意的还是错误?
我有一个函数可以计算我必须旋转矩阵中 x,y 点的某些列的量。该函数只需要一个输入 - 矩阵垫:
def rotate(mat):
在该函数中,我创建了 View 以便更轻松地处理每个部分:
rot_mat = mat[:,(col,col+1)]
然后,我计算一个旋转角度并将其应用回我之前创建的 View :
rot_mat[row,0] = cos(rot)*x - sin(rot)*y
rot_mat[row,1] = sin(rot)*x + cos(rot)*y
如果我在我的程序主体中执行此操作,对我的 rot_mat View 的更改将传播到原始矩阵垫。当我把它变成一个函数时, View 不再对原始矩阵产生副作用。这是什么原因,有什么办法可以解决这个问题吗?我还应该注意,它并没有在函数本身内改变垫子。最后,我只是尝试返回 mat 但没有进行任何更改。
完整的函数代码:
def rotate(mat):
# Get a reference shape
ref_sh = 2*random.choice(range(len(filelist)))
print 'Reference shape is '
print (ref_sh/2)
# Create a copy of the reference point matrix
ref_mat = mat.take([ref_sh,ref_sh+1],axis=1)
# Calculate rotation for each set of points
for col in range(len(filelist)):
col = col * 2 # Account for the two point columns
rot_mat = mat[:,(col,col+1)]
# Numerator = sum of wi*yi - zi*xi
numer = inner(ref_mat[:,0],rot_mat[:,1]) - inner(ref_mat[:,1],rot_mat[:,0])
# Denominator = sum of wi*xi + zi*yi
denom = inner(ref_mat[:,0],rot_mat[:,0]) + inner(ref_mat[:,1],rot_mat[:,1])
rot = arctan(numer/denom)
# Rotate the points in rot_mat. As it's a view of mat, the effects are
# propagated.
for row in range(num_points):
x = rot_mat[row,0]
y = rot_mat[row,1]
rot_mat[row,0] = cos(rot)*x - sin(rot)*y
rot_mat[row,1] = sin(rot)*x + cos(rot)*y
return mat
最佳答案
当您执行 view = A[:,(1,2)]
时,您正在使用高级索引 ( Numpy manual: Advanced Indexing ),这意味着该数组返回一个副本,而不是一个 View 。它之所以先进,是因为您的索引对象是一个“至少包含一个序列”的元组(该序列是元组 (1,2)
)。在您的情况下,总的显式选择对象 obj
将等于 (slice(None), (1,2))
,即 A[(slice(None), (1,2))]
返回与 A[:,(1,2)]
相同的内容。
正如 larsmans 上面所建议的,似乎 __getitem__
和 __setitem__
对于高级索引的行为不同,这是有道理的,因为将值分配给副本没有用(不会存储副本)。
关于python - 函数中的矩阵 View 没有副作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9418614/