Search code examples
pythonnumpydimension

How to double the dimension of a matrix while quartering the values?


I want to achieve this:

a = np.array ([[1, 2],
               [2, 1]])

b = np.array ([[0.25, 0.25, 0.5, 0.5],
               [0.25, 0.25, 0.5, 0.5],
               [0.5, 0.5, 0.25, 0.25],
               [0.5, 0.5, 0.25, 0.25])

Mathematically they r not the same matrices. But i think you get the idea what i want to do. I want to double the dimension of a matrix. But therefore i want to keep the information from the initial matrix a by take the quarter for the four corresponding cells.

Does some1 knows how to do this efficiently in numpy?


Solution

  • Here's one with np.broadcast_to that leverages broadcasting to avoid two stages of replications or tiling for performance benefits by doing it one -

    # "Expand" array a by Height, H and Width, W
    def expand_blockavg(a, H, W): 
        m,n = a.shape
        return np.broadcast_to((a/float(H*W))[:,None,:,None],(m,H,n,W)).reshape(m*H,-1)
    

    Sample runs -

    In [93]: a
    Out[93]: 
    array([[1, 2],
           [2, 1]])
    
    In [94]: expand_blockavg(a, H=2, W=2)
    Out[94]: 
    array([[0.25, 0.25, 0.5 , 0.5 ],
           [0.25, 0.25, 0.5 , 0.5 ],
           [0.5 , 0.5 , 0.25, 0.25],
           [0.5 , 0.5 , 0.25, 0.25]])
    
    In [95]: expand_blockavg(a, H=2, W=3)
    Out[95]: 
    array([[0.17, 0.17, 0.17, 0.33, 0.33, 0.33],
           [0.17, 0.17, 0.17, 0.33, 0.33, 0.33],
           [0.33, 0.33, 0.33, 0.17, 0.17, 0.17],
           [0.33, 0.33, 0.33, 0.17, 0.17, 0.17]])
    

    Runtime test on a large array -

    In [2]: a = np.random.rand(200,200)
    
    # Expand by (2 x 2)
    # @Kasrâmvd's soln
    In [85]: %timeit np.repeat(np.repeat(a, 2, 1), 2, 0)/4
    1000 loops, best of 3: 492 µs per loop
    
    In [86]: %timeit expand_blockavg(a, H=2, W=2)
    1000 loops, best of 3: 382 µs per loop
    
    # Expand by (20 x 20)
    # @Kasrâmvd's soln
    In [5]: %timeit np.repeat(np.repeat(a, 20, 1), 20, 0)/400
    10 loops, best of 3: 32 ms per loop
    
    In [6]: %timeit expand_blockavg(a, H=20, W=20)
    10 loops, best of 3: 20.1 ms per loop
    

    Larger array with (2 x 2) expansion -

    In [87]: a = np.random.rand(2000,2000)
    
    # @Kasrâmvd's soln
    In [88]: %timeit np.repeat(np.repeat(a, 2, 1), 2, 0)/4
    10 loops, best of 3: 70.2 ms per loop
    
    In [89]: %timeit expand_blockavg(a, H=2, W=2)
    10 loops, best of 3: 51.6 ms per loop