0

I have a function that calculates some ratios between two large np.arrays (>1000L, >1000L):

def error(crm1, crm2):

    delta1 = np.zeros((crm1.shape[0], crm1.shape[1]))
    delta2 = np.zeros((crm2.shape[0], crm2.shape[1]))
    stt = np.int(crm1.shape[0])
    stp = np.int(crm1.shape[1])

    for m in xrange(stt):
        for n in xrange(stp):
            s1 = crm1[m, n]
            s2 = crm2[m, n]

            w1 = (min(s1, s2)**2)/s1
            w2 = (min(s1, s2)**2)/s2

        delta1[m, n] = w1
        delta2[m, n] = w2

    return (delta1, delta2)

Now I realised that I have to calculate this ratio between an variable amount of np.arrays (same dimension and data type) like:

# Case 1
error(array1, array2)

# Case 2
error(array1, array2, array3, array4)

# Case 3
error(array1, array2, array3, array4, array5, array6)

If it´s possible, I don´t want to write a code for each case because I have many function like the error() function. Is it possible to change the code with the result that the function works with an variable amount of np.arrays?

Petermailpan
  • 103
  • 1
  • 10
  • 3
    Possible duplicate of [Can a variable number of arguments be passed to a function?](http://stackoverflow.com/questions/919680/can-a-variable-number-of-arguments-be-passed-to-a-function) – Jean-François Fabre Oct 12 '16 at 12:25
  • 2
    By the way you can do `np.zeros_like(crm1)` I think...it's simpler. – John Zwinck Oct 12 '16 at 12:34
  • @JohnZwinck It would probably be safer to use `np.zeros_like(crm1, dtype=np.float64)`, in case the caller passes in an array with an integer data type. – Warren Weckesser Oct 12 '16 at 12:38
  • 1
    @petermailpan Why do you have `+1` in `for n in xrange(stp+1):`? That will make the last value of `n` too big to be a second index of `crm1` and result in an `IndexError`. – Warren Weckesser Oct 12 '16 at 12:46
  • @JohnZwinck that is a brilliant tip! Thank you! – Petermailpan Oct 12 '16 at 12:56
  • @Jean-FrançoisFabre thank you for your suggestion. I have tried this a few hours ago but I was not able to return the variables. I could only print the results, so I could not save the results as an array. – Petermailpan Oct 12 '16 at 12:59
  • @WarrenWeckesser You are right. That was my mistake because I copy - paste an old script by accident. – Petermailpan Oct 12 '16 at 13:01
  • 1
    Also why not use `delta1 = np.minimum(crm1, crm2)**2/crm1` (assuming `crm2` has the same shape as `crm1`) instead of looping? it should be way faster. – P. Camilleri Oct 12 '16 at 13:17
  • @P.Camilleri because I need the minimum of the elements "crm1[0,0] and crm2[0,0]" and I want to divide this with crm1[0,0] and crm2[0,0]. Ok. I've tested it and it´s awesome that this works like the way you told me. It´s really faster. Thank you very much!!!! Would the way you wrote work with all mathematical operations? – Petermailpan Oct 12 '16 at 13:30

1 Answers1

1

You can use *args (the important thing is prefixing the argument name with *, you could call your argument *foo). You should also use numpy vectorization instead of looping through the array.

import numpy as np
def err(*args):
     # compute the pointwise min once and for all
     pointwise_min2 = np.minimum(*args)**2
     return tuple([pointwise_min2/arr for arr in args])

(if all the arrays have same shape, which I assumed since otherwise the calculation in your question makes no sense).

P. Camilleri
  • 12,664
  • 7
  • 41
  • 76
  • Now I get it. It returns a tuple with all the ratios for the amount of *args and I am able to extract the individual ratios with indexing the tuple. Thank you all very much for your advices! – Petermailpan Oct 12 '16 at 13:54
  • 1
    You can also unpack the tuple directly: `delta1, delta2 = err(crm1, crm2)` – P. Camilleri Oct 12 '16 at 14:01