Choices or assignments with np.ix_ with indexing or logical arrays / masks
1. With indexing-arrays
A. Choice
We can use np.ix_ to get np.ix_ index arrays that can be broadcast against each other, which leads to multidimensional index combinations. Thus, when this tuple is used for indexing in the input array, we get the same multidimensional array. Therefore, to make a selection based on two 1D index arrays, it would be:
x_indexed = x[np.ix_(row_indices,col_indices)]
B. Purpose
We can use the same record to assign a scalar or broadcast array to these indexed positions. Consequently, the following work for assignments -
x[np.ix_(row_indices,col_indices)] = # scalar or broadcastable array
masks
We can also use logical arrays / masks with np.ix_ , similar to how index arrays are used. This can be used again to select a block from the input array, as well as for assignments in it.
A. Choice
Thus, with boolean arrays row_mask and col_mask as masks for selecting rows and columns respectively, we can use the following to select:
x[np.ix_(row_mask,col_mask)]
B. Purpose
And the following work for assignments -
x[np.ix_(row_mask,col_mask)] = # scalar or broadcastable array
Test runs
Using np.ix_ with indexing-arrays
Input Array and Index Arrays -
In [221]: x Out[221]: array([[17, 39, 88, 14, 73, 58, 17, 78], [88, 92, 46, 67, 44, 81, 17, 67], [31, 70, 47, 90, 52, 15, 24, 22], [19, 59, 98, 19, 52, 95, 88, 65], [85, 76, 56, 72, 43, 79, 53, 37], [74, 46, 95, 27, 81, 97, 93, 69], [49, 46, 12, 83, 15, 63, 20, 79]]) In [222]: row_indices Out[222]: [4, 2, 5, 4, 1] In [223]: col_indices Out[223]: [1, 2]
A tuple of indexed arrays using np.ix_ -
In [224]: np.ix_(row_indices,col_indices) # Broadcasting of indices Out[224]: (array([[4], [2], [5], [4], [1]]), array([[1, 2]]))
Make a choice -
In [225]: x[np.ix_(row_indices,col_indices)] Out[225]: array([[76, 56], [70, 47], [46, 95], [76, 56], [92, 46]])
As suggested by OP , this is actually the same as performing old-school broadcasting with a version of the two-dimensional row_indices array, whose elements / indices are sent along axis=0 and thus creating a singleton dimension to axis=1 which allows broadcasting with col_indices , So we would have an alternative solution, like so -
In [227]: x[np.asarray(row_indices)[:,None],col_indices] Out[227]: array([[76, 56], [70, 47], [46, 95], [76, 56], [92, 46]])
As mentioned earlier, for assignments we just do it.
Row, col, array indexing -
In [36]: row_indices = [1, 4] In [37]: col_indices = [1, 3]
Doing tasks with a scalar -
In [38]: x[np.ix_(row_indices,col_indices)] = -1 In [39]: x Out[39]: array([[17, 39, 88, 14, 73, 58, 17, 78], [88, -1, 46, -1, 44, 81, 17, 67], [31, 70, 47, 90, 52, 15, 24, 22], [19, 59, 98, 19, 52, 95, 88, 65], [85, -1, 56, -1, 43, 79, 53, 37], [74, 46, 95, 27, 81, 97, 93, 69], [49, 46, 12, 83, 15, 63, 20, 79]])
Make assignments with a 2D block (broadcast array) -
In [40]: rand_arr = -np.arange(4).reshape(2,2) In [41]: x[np.ix_(row_indices,col_indices)] = rand_arr In [42]: x Out[42]: array([[17, 39, 88, 14, 73, 58, 17, 78], [88, 0, 46, -1, 44, 81, 17, 67], [31, 70, 47, 90, 52, 15, 24, 22], [19, 59, 98, 19, 52, 95, 88, 65], [85, -2, 56, -3, 43, 79, 53, 37], [74, 46, 95, 27, 81, 97, 93, 69], [49, 46, 12, 83, 15, 63, 20, 79]])
Using np.ix_ with masks
Input Array -
In [19]: x Out[19]: array([[17, 39, 88, 14, 73, 58, 17, 78], [88, 92, 46, 67, 44, 81, 17, 67], [31, 70, 47, 90, 52, 15, 24, 22], [19, 59, 98, 19, 52, 95, 88, 65], [85, 76, 56, 72, 43, 79, 53, 37], [74, 46, 95, 27, 81, 97, 93, 69], [49, 46, 12, 83, 15, 63, 20, 79]])
Entering a string, col masks -
In [20]: row_mask = np.array([0,1,1,0,0,1,0],dtype=bool) In [21]: col_mask = np.array([1,0,1,0,1,1,0,0],dtype=bool)
Make a choice -
In [22]: x[np.ix_(row_mask,col_mask)] Out[22]: array([[88, 46, 44, 81], [31, 47, 52, 15], [74, 95, 81, 97]])
Doing tasks with a scalar -
In [23]: x[np.ix_(row_mask,col_mask)] = -1 In [24]: x Out[24]: array([[17, 39, 88, 14, 73, 58, 17, 78], [-1, 92, -1, 67, -1, -1, 17, 67], [-1, 70, -1, 90, -1, -1, 24, 22], [19, 59, 98, 19, 52, 95, 88, 65], [85, 76, 56, 72, 43, 79, 53, 37], [-1, 46, -1, 27, -1, -1, 93, 69], [49, 46, 12, 83, 15, 63, 20, 79]])
Make assignments with a 2D block (broadcast array) -
In [25]: rand_arr = -np.arange(12).reshape(3,4) In [26]: x[np.ix_(row_mask,col_mask)] = rand_arr In [27]: x Out[27]: array([[ 17, 39, 88, 14, 73, 58, 17, 78], [ 0, 92, -1, 67, -2, -3, 17, 67], [ -4, 70, -5, 90, -6, -7, 24, 22], [ 19, 59, 98, 19, 52, 95, 88, 65], [ 85, 76, 56, 72, 43, 79, 53, 37], [ -8, 46, -9, 27, -10, -11, 93, 69], [ 49, 46, 12, 83, 15, 63, 20, 79]])