Fancy indexing and index tricks

Indexing with Arrays of Indices

>>> a = np.arange(12)**2                       # the first 12 square numbers
>>> i = np.array( [ 1,1,3,8,5 ] )              # an array of indices
>>> a[i]                                       # the elements of a at the positions i
array([ 1,  1,  9, 64, 25])
>>>
>>> j = np.array( [ [ 3, 4], [ 9, 7 ] ] )      # a bidimensional array of indices
>>> a[j]                                       # the same shape as j
array([[ 9, 16],
       [81, 49]])
>>> let a = build 12 (^2) :: Vector Z
>>> let i = fromList [1,1,3,8,5] :: Vector I
>>> flatten ((asRow a) ?? (All, Pos i))
[1,1,9,64,25]
>>> let j = fromLists [[3,4],[9,7]] :: Matrix I
>>> remap (asRow (scalar 0)) (j) ((fromRows . replicate (rows j)) a)
(2><2)
 [  9, 16
 , 81, 49 ]
>>> palette = np.array( [ [0,0,0],                # black
...                       [255,0,0],              # red
...                       [0,255,0],              # green
...                       [0,0,255],              # blue
...                       [255,255,255] ] )       # white
>>> image = np.array( [ [ 0, 1, 2, 0 ],           # each value corresponds to a color in the palette
...                     [ 0, 3, 4, 0 ]  ] )
>>> palette[image]                            # the (2,4,3) color image
array([[[  0,   0,   0],
        [255,   0,   0],
        [  0, 255,   0],
        [  0,   0,   0]],
       [[  0,   0,   0],
        [  0,   0, 255],
        [255, 255, 255],
        [  0,   0,   0]]])
>>> let palette = fromLists [[0,0,0],[255,0,0],[0,255,0],[0,0,255],[255,255,255]] :: Matrix I
>>> let image = fromLists [[0,1,2,0],[0,3,4,0]] :: Matrix I
>>> fmap (\img -> palette ?? (Pos img, All)) (toRows image) -- almost 3D, [Matrix Z] instead
[(4><3)
 [   0,   0, 0
 , 255,   0, 0
 ,   0, 255, 0
 ,   0,   0, 0 ],(4><3)
 [   0,   0,   0
 ,   0,   0, 255
 , 255, 255, 255
 ,   0,   0,   0 ]]
>>> a = np.arange(12).reshape(3,4)
>>> a
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> i = np.array( [ [0,1],                        # indices for the first dim of a
...                 [1,2] ] )
>>> j = np.array( [ [2,1],                        # indices for the second dim
...                 [3,3] ] )
>>>
>>> a[i,j]                                     # i and j must have equal shape
array([[ 2,  5],
       [ 7, 11]])
>>>
>>> a[i,2]
array([[ 2,  6],
       [ 6, 10]])
>>>
>>> a[:,j]                                     # i.e., a[ : , j]
array([[[ 2,  1],
        [ 3,  3]],
       [[ 6,  5],
        [ 7,  7]],
       [[10,  9],
        [11, 11]]])
>>> let a = (3><4) [0::Z ..]
>>> let i = fromLists [[0,1],[1,2]] :: Matrix I
>>> let j = fromLists [[2,1],[3,3]] :: Matrix I
>>> remap i j a
(2><2)
 [ 2,  5
 , 7, 11 ]
>>> remap i (asColumn (scalar 2)) a
(2><2)
 [ 2,  6
 , 6, 10 ]
>>> fmap (\r -> remap (asRow (scalar r)) j a) (toList ((rows a) |> [0..])) -- emulating 3D
[(2><2)
 [ 2, 1
 , 3, 3 ],(2><2)
 [ 6, 5
 , 7, 7 ],(2><2)
 [ 10,  9
 , 11, 11 ]]
>>> time = np.linspace(20, 145, 5)                 # time scale
>>> data = np.sin(np.arange(20)).reshape(5,4)      # 4 time-dependent series
>>> time
array([  20.  ,   51.25,   82.5 ,  113.75,  145.  ])
>>> data
array([[ 0.        ,  0.84147098,  0.90929743,  0.14112001],
       [-0.7568025 , -0.95892427, -0.2794155 ,  0.6569866 ],
       [ 0.98935825,  0.41211849, -0.54402111, -0.99999021],
       [-0.53657292,  0.42016704,  0.99060736,  0.65028784],
       [-0.28790332, -0.96139749, -0.75098725,  0.14987721]])
>>>
>>> ind = data.argmax(axis=0)                   # index of the maxima for each series
>>> ind
array([2, 0, 3, 1])
>>>
>>> time_max = time[ ind]                       # times corresponding to the maxima
>>>
>>> data_max = data[ind, xrange(data.shape[1])] # => data[ind[0],0], data[ind[1],1]...
>>>
>>> time_max
array([  82.5 ,   20.  ,  113.75,   51.25])
>>> data_max
array([ 0.98935825,  0.84147098,  0.99060736,  0.6569866 ])
>>>
>>> np.all(data_max == data.max(axis=0))
True
>>> let time = linspace 5 (20.0, 145.0) :: Vector R
>>> let ydata = cmap sin ((5><4) [0..]) :: Matrix R -- data is a protected word
>>> time
[20.0,51.25,82.5,113.75,145.0]
>>> ydata
(5><4)
 [                 0.0,  0.8414709848078965,   0.9092974268256817,  0.1411200080598672
 , -0.7568024953079282, -0.9589242746631385, -0.27941549819892586,  0.6569865987187891
 ,  0.9893582466233818,  0.4121184852417566,  -0.5440211108893698, -0.9999902065507035
 , -0.5365729180004349,  0.4201670368266409,   0.9906073556948704,  0.6502878401571168
 , -0.2879033166650653, -0.9613974918795568,   -0.750987246771676, 0.14987720966295234 ]
>>> let ind = fmap maxIndex (toColumns ydata)
>>> ind
[2,0,3,1]
>>> let time_max = flatten ((asRow time) ?? (All, Pos (idxs ind)))
>>> let ydata_max = takeDiag (ydata ?? (Pos (idxs ind), All))
>>> time_max
[82.5,20.0,113.75,51.25]
>>> ydata_max
[0.9893582466233818,0.8414709848078965,0.9906073556948704,0.6569865987187891]
>>> (toList ydata_max) == (fmap maxElement (toColumns ydata))
True
>>> a = np.arange(5)
>>> a
array([0, 1, 2, 3, 4])
>>> a[[1,3,4]] = 0
>>> a
array([0, 0, 2, 0, 0])
>>> a = np.arange(5)
>>> a[[0,0,2]]=[1,2,3]
>>> a
array([2, 1, 3, 3, 4])
>>> a = np.arange(5)
>>> a[[0,0,2]]+=1
>>> a
array([1, 1, 3, 3, 4])
>>> let a = 5 |> [0..] :: Vector Z
>>> a
[0,1,2,3,4]
>>> let a' = accum a const (zip [1,3,4] (repeat 0))
>>> a'
[0,0,2,0,0]
>>> let a' = accum a const (zip [1,2,3] [0,0,2])
>>> a'
[0,0,0,2,4]
>>> let a' = accum a (+) (zip [0,0,2] (repeat 1))
>>> a' -- this DOES work, since we hit the 0 index twice mutably
[2,1,3,3,4]

Indexing with Boolean Arrays

>>> a = np.arange(12).reshape(3,4)
>>> b = a > 4
>>> b                                          # b is a boolean with a's shape
array([[False, False, False, False],
       [False,  True,  True,  True],
       [ True,  True,  True,  True]], dtype=bool)
>>> a[b]                                       # 1d array with the selected elements
array([ 5,  6,  7,  8,  9, 10, 11])
>>> a[b] = 0                                   # All elements of 'a' higher than 4 become 0
>>> a
array([[0, 1, 2, 3],
       [4, 0, 0, 0],
       [0, 0, 0, 0]])
>>> let a = (3><4) [0..] :: Matrix Z
>>> let b = (fmap (fmap (>4))) (toLists a) -- gives a [[Bool]], which is not that useful
>>> let b = find (>4) a                    -- better than just Matrix Bool, which does not work in hmatrix
>>> b                                      -- a [IndexOf c] is more idiomatic
[(1,1),(1,2),(1,3),(2,0),(2,1),(2,2),(2,3)]
>>> fromList (fmap (atIndex a) b)
[5,6,7,8,9,10,11]
>>> accum a const (zip b (repeat 0))
(3><4)
 [ 0, 1, 2, 3
 , 4, 0, 0, 0
 , 0, 0, 0, 0 ]
>>> a = np.arange(12).reshape(3,4)
>>> b1 = np.array([False,True,True])             # first dim selection
>>> b2 = np.array([True,False,True,False])       # second dim selection
>>>
>>> a[b1,:]                                   # selecting rows
array([[ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>>
>>> a[b1]                                     # same thing
array([[ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>>
>>> a[:,b2]                                   # selecting columns
array([[ 0,  2],
       [ 4,  6],
       [ 8, 10]])
>>>
>>> a[b1,b2]                                  # a weird thing to do
array([ 4, 10])
>>> let a = (3><4) [0..] :: Matrix Z
>>> let b1' = [False,True,True]
>>> let b2' = [True,False,True,False]
>>> import Data.List (elemIndices)
>>> let helper = elemIndices True
>>> let b1 = helper b1'
>>> let b2 = helper b2'
>>> a ?? (Pos (idxs b1), All)
(2><4)
 [ 4, 5,  6,  7
 , 8, 9, 10, 11 ]
>>> a ? b1
(2><4)
 [ 4, 5,  6,  7
 , 8, 9, 10, 11 ]
>>> a ?? (All, Pos (idxs b2))
(3><2)
 [ 0,  2
 , 4,  6
 , 8, 10 ]
>>> a ?? (Pos (idxs b1), Pos (idxs b2))       -- unlike numpy, will return matrix that matches any combination from selections
(2><2)
 [ 4,  6
 , 8, 10 ]
>>> (fromList . fmap (atIndex a)) (zip b1 b2) -- this will give you the numpy result, the zipped indexing of a matrix to give a vector
[4,10]