rougier / numpy-100

100 numpy exercises (with solutions)
MIT License
12.05k stars 5.7k forks source link

An alternative solution for Q.76 #162

Closed iamyifan closed 2 years ago

iamyifan commented 2 years ago
  1. Consider a one-dimensional array Z, build a two-dimensional array whose first row is (Z[0],Z[1],Z[2]) and each subsequent row is shifted by 1 (last row should be (Z[-3],Z[-2],Z[-1]) (★★★) hint: from numpy.lib import stride_tricks

    # Author: Joe Kington / Erik Rigtorp from numpy.lib import stride_tricks

def rolling(a, window): shape = (a.size - window + 1, window) strides = (a.strides[0], a.strides[0]) return stride_tricks.as_strided(a, shape=shape, strides=strides) Z = rolling(np.arange(10), 3) print(Z)

Same as the last issue, sliding_window_view is an easier function in NumPy. The new solution will be:

Z = np.arange(10)
print(sliding_window_view(Z, window_shape=(3)))
iamyifan commented 2 years ago
  1. Consider an array Z = [1,2,3,4,5,6,7,8,9,10,11,12,13,14], how to generate an array R = [[1,2,3,4], [2,3,4,5], [3,4,5,6], ..., [11,12,13,14]]? (★★★) hint: stride_tricks.as_strided

# Author: Stefan van der Walt

Z = np.arange(1,15,dtype=np.uint32) R = stride_tricks.as_strided(Z,(11,4),(4,4)) print(R)

Q.81 can also be optimized by sliding_window_view.

Z = np.arange(1,15,dtype=np.uint32)
print(sliding_window_view(Z, 4))
iamyifan commented 2 years ago
  1. Extract all the contiguous 3x3 blocks from a random 10x10 matrix (★★★) hint: stride_tricks.as_strided

# Author: Chris Barker

Z = np.random.randint(0,5,(10,10)) n = 3 i = 1 + (Z.shape[0]-3) j = 1 + (Z.shape[1]-3) C = stride_tricks.as_strided(Z, shape=(i, j, n, n), strides=Z.strides + Z.strides) print(C)

An alternative solution will be:

Z = np.random.randint(0,5,(10,10))
print(sliding_window_view(Z, (3, 3)))
iamyifan commented 2 years ago
  1. Consider a 16x16 array, how to get the block-sum (block size is 4x4)? (★★★) hint: np.add.reduceat

# Author: Robert Kern

Z = np.ones((16,16)) k = 4 S = np.add.reduceat(np.add.reduceat(Z, np.arange(0, Z.shape[0], k), axis=0), np.arange(0, Z.shape[1], k), axis=1) print(S)

# alternative solution: # Author: Sebastian Wallkötter (@FirefoxMetzger)

Z = np.ones((16,16)) k = 4

windows = np.lib.stride_tricks.sliding_window_view(Z, (k, k)) S = windows[::k, ::k, ...].sum(axis=(-2, -1))

The alternative solution will be:

Z = np.ones((16, 16))
k = 4
print(sliding_window_view(Z, window_shape=(k, k))[::k, ::k].sum(-1).sum(-1))
FirefoxMetzger commented 2 years ago

@Jeff1999 It is of course a matter of taste, but .sum([-2, -1]) might be easier to read than .sum(-1).sum(-1).

Also, since you are omitting kwargs everywhere else, maybe sliding_window_view(Z, (k, k)) may be more consistent and shorter.

rougier commented 2 years ago

Can you post output of the original and new implementation to make sure we get the same output?

iamyifan commented 2 years ago

@rougier I made an online notebook on Datalore. https://datalore.jetbrains.com/view/notebook/55zIzAUVqqPyOUW3bDe2jN

rougier commented 2 years ago

Perfect! If you can make (individual) PR, that would be fantastic.