[英]Multi dimensional Indexing with Numpy
我正在使用一个 3 维数组,其定义如下:
x = np.zeros((dim1, dim2, dim3), dtype=np.float32)
插入一些数据后,仅当特定列中的值仍然为零时,我才需要应用函数。 我感兴趣的列由包含正确索引的数组选择
scale_idx = np.array([0,1,3])
因此我要做的是使用索引来选择那些行和列。
起初我尝试这样做,对前二维使用布尔掩码,对第三维使用数组:
x[x[:,:,scale_idx].any(axis =2)] ,scale_idx]
但我收到此错误:
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (2,) (2,) (3,)
如果我将最后一个索引更改为:
我得到了我感兴趣的所有行,但我得到了所有可能的列,我期望最后一个数组将充当索引器,如https://docs.scipy 中所述.org/doc/numpy/user/basics.indexing.html 。
x[x[:,:,scale_idx].any(axis =2)]
我的scale_idx
应该被解释为列索引器,但实际上被解释为行索引,因此,由于只有 2 行符合条件但我有 3 个索引,我得到一个IndexError
。
我找到了一种解决方法,使用
x[x[:,:,scale_idx].any(axis =2)][:,:,scale_idx]
但它有点难看,因为它是一个切片,我无法修改原始数组。
有人愿意向我解释我做错了什么吗?
编辑:感谢@hpaulj,我设法隔离了我需要的单元格,之后我创建了一个与所选值形状相同的矩阵,并将这些值分配给蒙面单元格,令我惊讶的是,新值不是我刚刚设置的那些,而是一些我无法弄清楚它们来自哪里的随机整数。 重现代码:
scale_idx = np.array([0,3,1])
b = x[:,:,scale_idx].any(axis =2)
I, J = np.nonzero(b)
x[I[:,None], J[:,None], scale_idx] #this selects the correct cells
>>>
array([[ 50, 50, 50],
[100, 100, 100],
[100, 100, 100]])
scaler.transform(x[I[:,None], J[:,None], scale_idx]) #sklearn standard scaler, returns a matrix with the scaled values
>>>
array([[-0.50600345, -0.5445559 , -1.2957878 ],
[-0.50600345, -0.25915199, -1.22266904],
[-0.50600345, -0.25915199, -1.22266904]])
x[I[:,None], J[:,None], scale_idx] = scaler.transform(x[I[:,None], J[:,None], scale_idx]) #assign the new values to the selected cells
x[I[:,None], J[:,None], scale_idx] #check the new values
array([[0, 2, 0],
[0, 6, 2],
[0, 6, 2]])
为什么新值与我期望的不同?
让我们从indexing
文档中获取 3d 布尔掩码示例:
In [135]: x = np.arange(30).reshape(2,3,5)
...: b = np.array([[True, True, False], [False, True, True]])
In [136]: x
Out[136]:
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]],
[[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]]])
In [137]: b
Out[137]:
array([[ True, True, False],
[False, True, True]])
In [138]: x[b]
Out[138]:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]])
这是一个二维数组。 掩码b
从前 2 个维度中选择元素。 False
值导致它跳过 [10...] 和 [15...] 行。
我们可以在最后一个维度上切片:
In [139]: x[b,:3]
Out[139]:
array([[ 0, 1, 2],
[ 5, 6, 7],
[20, 21, 22],
[25, 26, 27]])
但是列表索引会产生错误(除非它的长度为 4):
In [140]: x[b,[0,1,2]]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-140-7f1dbec100f2> in <module>
----> 1 x[b,[0,1,2]]
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (4,) (4,) (3,)
原因是布尔掩码有效地转换为np.where
数组的索引:
In [141]: np.nonzero(b)
Out[141]: (array([0, 0, 1, 1]), array([0, 1, 1, 2]))
nonzero
找到 4 个非零元素。 x[b]
索引是:
In [143]: x[[0,0,1,1],[0,1,1,2],:]
Out[143]:
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]])
https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#boolean-array-indexing
然后形状不匹配变得更加明显:
In [144]: x[[0,0,1,1],[0,1,1,2],[1,2,3]]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-144-1efd76049cb0> in <module>
----> 1 x[[0,0,1,1],[0,1,1,2],[1,2,3]]
IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes (4,) (4,) (3,)
如果列表大小匹配,则索引会运行,但会生成“对角线”,而不是块:
In [145]: x[[0,0,1,1],[0,1,1,2],[1,2,3,4]]
Out[145]: array([ 1, 7, 23, 29])
正如您发现两阶段索引工作 - 但不适用于设置值
In [146]: x[[0,0,1,1],[0,1,1,2]][:,[1,2,3]]
Out[146]:
array([[ 1, 2, 3],
[ 6, 7, 8],
[21, 22, 23],
[26, 27, 28]])
我们可以通过“转置”最后一个索引列表来获取块:
In [147]: x[[0,0,1,1],[0,1,1,2],[[1],[2],[3]]]
Out[147]:
array([[ 1, 6, 21, 26],
[ 2, 7, 22, 27],
[ 3, 8, 23, 28]])
好的,这是转置。 我们可以对其应用转置。 或者我们可以先转置b
数组:
In [148]: I,J=np.nonzero(b)
In [149]: x[I[:,None], J[:,None], [1,2,3]]
Out[149]:
array([[ 1, 2, 3],
[ 6, 7, 8],
[21, 22, 23],
[26, 27, 28]])
这适用于设置
In [150]: x[I[:,None], J[:,None], [1,2,3]]=0
In [151]: x
Out[151]:
array([[[ 0, 0, 0, 0, 4],
[ 5, 0, 0, 0, 9],
[10, 11, 12, 13, 14]],
[[15, 16, 17, 18, 19],
[20, 0, 0, 0, 24],
[25, 0, 0, 0, 29]]])
这是一个很长的答案。 我对正在发生的事情有一个大致的了解,但需要弄清楚细节。 另外,您需要了解正在发生的事情。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.