user2963882
user2963882

Reputation: 627

Numpy divide on ndarray

I want to create a new array containing the ratios of another ndarray.

First simple example:

import numpy as np
week = np.full((3, 4), 2, dtype=float)
week[:,2] = 0
week[2,0:2] =0
week[0,3] =0.99
week[1,3] =1.99
week[2,3] =0.89

week

returns

array([[2.  , 2.  , 0.  , 0.99],
       [2.  , 2.  , 0.  , 1.99],
       [0.  , 0.  , 0.  , 0.89]])

Now I want to calculate a ndarray containing the ratios of week[:,3]

ratio =  week[:,3].reshape(1,-1).T/ week[:,3]

returns

array([[1.   , 0.497, 1.112],
       [2.01 , 1.   , 2.236],
       [0.899, 0.447, 1.   ]])

exactly what I want.

More general case A 5d array where the first 4 dimensions can change

weeks_5d= np.full((1,1,2, 3, 4), 2, dtype=float)
weeks_5d[:,:,:,:,2] = 0
weeks_5d[:,:,0,2,0:2] =0
weeks_5d[:,:,1,1,0:2] =0
weeks_5d[:,:,:,0,3] = 0.99
weeks_5d[:,:,:,1,3] = 1.99
weeks_5d[:,:,:,2,3] = 0.89

weeks_5d

returns

array([[[[[2.  , 2.  , 0.  , 0.99],
          [2.  , 2.  , 0.  , 1.99],
          [0.  , 0.  , 0.  , 0.89]],

         [[2.  , 2.  , 0.  , 0.99],
          [0.  , 0.  , 0.  , 1.99],
          [2.  , 2.  , 0.  , 0.89]]]]])

Now I want to calculate the same ratio for each ndarray

Transposing the 5darray returns weird results.

What I need is

   array([[[[[1.   , 0.497, 1.112],
              [2.01 , 1.   , 2.236],
              [0.899, 0.447, 1.   ]]],

             [[1.   , 0.497, 1.112],
              [2.01 , 1.   , 2.236],
              [0.899, 0.447, 1.   ]]]]])

Upvotes: 0

Views: 410

Answers (1)

Vince W.
Vince W.

Reputation: 3785

I think a loop is your best hope here and there is a slow and a fast way to do it:

the slow way:

def get_ratios(arr):
    ni, nj, nk = arr.shape[:3]
    last_dim = arr.shape[3]

    new_arr = np.zeros(shape=(ni, nj, nk, last_dim, last_dim),
                       dtype=np.float64)
    for i in range(ni):
        for j in range(nj):
            for k in range(nk):
                week = arr[i, j, k]
                ratio = week[:, 3].reshape(-1, 1) / week[:, 3]
                new_arr[i, j, k] = ratio

    return new_arr

get_ratios(weeks_5d)

prints

array([[[[[1.        , 0.49748744, 1.11235955],
          [2.01010101, 1.        , 2.23595506],
          [0.8989899 , 0.44723618, 1.        ]],

         [[1.        , 0.49748744, 1.11235955],
          [2.01010101, 1.        , 2.23595506],
          [0.8989899 , 0.44723618, 1.        ]]]]])

Obviously looping over arrays in python is slow but that's what numba was invented for:

the fast(er) way

from numba import njit

@njit
def get_ratios(arr):
    ni, nj, nk = arr.shape[:3]
    last_dim = arr.shape[3]

    new_arr = np.zeros(shape=(ni, nj, nk, last_dim, last_dim),
                       dtype=np.float64)
    for i in range(ni):
        for j in range(nj):
            for k in range(nk):
                week = arr[i, j, k, :, 3]
                for d1 in range(last_dim):
                    for d2 in range(last_dim):
                        new_arr[i, j, k, d1, d2] = week[d1] / week[d2]

    return new_arr

get_ratios(weeks_5d)

prints

array([[[[[1.        , 0.49748744, 1.11235955],
          [2.01010101, 1.        , 2.23595506],
          [0.8989899 , 0.44723618, 1.        ]],

         [[1.        , 0.49748744, 1.11235955],
          [2.01010101, 1.        , 2.23595506],
          [0.8989899 , 0.44723618, 1.        ]]]]])

Upvotes: 1

Related Questions