value error when using 1d array for curve fitting

Viewed 35

I am getting this error when using Scipy curve fitting to get the fitting parameters (A,B,C,D). There is no problem with defined function and works well and responds well. There is also no problem when the x (x11, x22) and y array (used for curve fitting) are just one element array and not 1d array with some elements. I know that this problem is because of multi elements in the input array for fitting (x11, x22, y). Actually, I think it is because the code does not know to which element of array should apply the condition in the function. but, I do not how to solve it. Any help and suggestion would be appreciated!

Here is the code:

x11=fin[:,0]
x22=fin[:,1]
y=fin[:,2]

bin=[4,4.5,5,5.5]


def interpo(x,A,B, C, D):
    x1, x2=x
    if  bin[0] <= x1 <bin[1]:
        if np.logical_and(x2>= bin[0] , x2<bin[1]):
            f1=A + ((x1 -bin[0])/(bin[1]-bin[0]))*(B-A)
            f2=A + ((x2 -bin[0])/(bin[1]-bin[0]))*(B-A)
            kh=f2/f1
        if x2>= bin[1] and x2<bin[2]:
            f1=A + ((x1 -bin[0])/(bin[1]-bin[0]))*(B-A)
            f2=B + ((x2 -bin[1])/(bin[2]-bin[1]))*(C-B)
            kh=f2/f1
            
        if x2>= bin[2] and x2<bin[3]:
            f1=A + ((x1 -bin[0])/(bin[1]-bin[0]))*(B-A)
            f2=C + ((x2 -bin[2])/(bin[3]-bin[2]))*(D-C)
            kh=f2/f1
    if x1>= bin[1] and x1<bin[2]:
        if x2>= bin[1] and x2<bin[2]:
            f1=B + ((x1 -bin[1])/(bin[2]-bin[1]))*(C-B)
            f2=B + ((x2 -bin[1])/(bin[2]-bin[1]))*(C-B)
            kh=f2/f1
        if x2>= bin[2] and x2<bin[3]:
            f1=B + ((x1 -bin[1])/(bin[2]-bin[1]))*(C-B)
            f2=C + ((x2 -bin[2])/(bin[3]-bin[2]))*(D-C)
            kh=f2/f1
    if x1>= bin[2] and x1<bin[3]:
        if x2>= bin[2] and x2<bin[3]:
            f1=C + ((x1 -bin[2])/(bin[3]-bin[2]))*(D-C)
            f2=C + ((x2 -bin[2])/(bin[3]-bin[2]))*(D-C)
            kh=f2/f1
            
    return (kh)

popt, pcov = curve_fit(interpo, (x11,x22), y, method='lm')

And here is the error:

      Input In [3] in interpo
    if  bin[0] <= x1 <bin[1]:

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
2 Answers

In order to evaluate the values in x one by one, you can use the following function:

def interpo(x, A, B, C, D):
    result = []
    for x1, x2 in zip(x[0], x[1]):
        if  bin[0] <= x1 <bin[1]:
            if np.logical_and(x2>= bin[0] , x2<bin[1]):
                f1=A + ((x1 -bin[0])/(bin[1]-bin[0]))*(B-A)
                f2=A + ((x2 -bin[0])/(bin[1]-bin[0]))*(B-A)
                kh=f2/f1
            if x2>= bin[1] and x2<bin[2]:
                f1=A + ((x1 -bin[0])/(bin[1]-bin[0]))*(B-A)
                f2=B + ((x2 -bin[1])/(bin[2]-bin[1]))*(C-B)
                kh=f2/f1
                
            if x2>= bin[2] and x2<bin[3]:
                f1=A + ((x1 -bin[0])/(bin[1]-bin[0]))*(B-A)
                f2=C + ((x2 -bin[2])/(bin[3]-bin[2]))*(D-C)
                kh=f2/f1
        if x1>= bin[1] and x1<bin[2]:
            if x2>= bin[1] and x2<bin[2]:
                f1=B + ((x1 -bin[1])/(bin[2]-bin[1]))*(C-B)
                f2=B + ((x2 -bin[1])/(bin[2]-bin[1]))*(C-B)
                kh=f2/f1
            if x2>= bin[2] and x2<bin[3]:
                f1=B + ((x1 -bin[1])/(bin[2]-bin[1]))*(C-B)
                f2=C + ((x2 -bin[2])/(bin[3]-bin[2]))*(D-C)
                kh=f2/f1
        if x1>= bin[2] and x1<bin[3]:
            if x2>= bin[2] and x2<bin[3]:
                f1=C + ((x1 -bin[2])/(bin[3]-bin[2]))*(D-C)
                f2=C + ((x2 -bin[2])/(bin[3]-bin[2]))*(D-C)
                kh=f2/f1
        result.append(kh)        
    return result

I though again and for the purpose of fitting this function, it seems to need to process numpy arrays freely, so I would suggest to rewrite it like this as an alternative:

def interpo(x, A, B, C, D):
    x1, x2 = x
    temp = np.zeros((x1.shape[0], 3))
    
    cond = np.logical_and(x1 >= bin[0], x1 < bin[1]) & np.logical_and(x2 >= bin[0], x2 < bin[1])
    temp[cond, 0] = A + ((x1[cond] -bin[0])/(bin[1]-bin[0]))*(B-A)
    temp[cond, 1] = A + ((x2[cond] -bin[0])/(bin[1]-bin[0]))*(B-A)
    
    cond = np.logical_and(x1 >= bin[0], x1 < bin[1]) & np.logical_and(x2 >= bin[1], x2 < bin[2])
    temp[cond, 0] = A + ((x1[cond] -bin[0])/(bin[1]-bin[0]))*(B-A)
    temp[cond, 1] = B + ((x2[cond] -bin[1])/(bin[2]-bin[1]))*(C-B)
    
    cond = np.logical_and(x1 >= bin[0], x1 < bin[1]) & np.logical_and(x2 >= bin[2], x2 < bin[3])
    temp[cond, 0] = A + ((x1[cond] -bin[0])/(bin[1]-bin[0]))*(B-A)
    temp[cond, 1] = C + ((x2[cond] -bin[2])/(bin[3]-bin[2]))*(D-C)
    
    cond = np.logical_and(x1 >= bin[1], x1 < bin[2]) & np.logical_and(x2 >= bin[1], x2 < bin[2])
    temp[cond, 0] = B + ((x1[cond] -bin[1])/(bin[2]-bin[1]))*(C-B)
    temp[cond, 1] = B + ((x2[cond] -bin[1])/(bin[2]-bin[1]))*(C-B)
    
    cond = np.logical_and(x1 >= bin[1], x1 < bin[2]) & np.logical_and(x2 >= bin[2], x2 < bin[3])
    temp[cond, 0] = B + ((x1[cond] -bin[1])/(bin[2]-bin[1]))*(C-B)
    temp[cond, 1] = C + ((x2[cond] -bin[2])/(bin[3]-bin[2]))*(D-C)
    
    cond = np.logical_and(x1 >= bin[2], x1 < bin[3]) & np.logical_and(x2 >= bin[2], x2 < bin[3])
    temp[cond, 0] = C + ((x1[cond] -bin[2])/(bin[3]-bin[2]))*(D-C)
    temp[cond, 1] = C + ((x2[cond] -bin[2])/(bin[3]-bin[2]))*(D-C)

    temp[:,2] = np.divide(temp[:,0], temp[:,1])
            
    return temp[:,2]

But curve_fit() seems unable to fit the parameters for this function. See the code below:

import numpy as np
from scipy.optimize import curve_fit

x11 = np.random.uniform(0.0, 3.0, 100)
x22 = np.random.beta(2.3, 4.8, 100) * 3.0

x11_int = x11.astype(np.int64)
x22_int = x22.astype(np.int64)

x22[x22_int < x11_int] = x22[x22_int < x11_int] + 1.0
x11_int = x11.astype(np.int64)
x22_int = x22.astype(np.int64)
x22[x22_int < x11_int] = x22[x22_int < x11_int] + 1.0
x11 = x11 / 2.0 + 4.0
x22 = x22 / 2.0 + 4.0

def interpo(x, A, B, C, D):
    x1, x2 = x
    temp = np.zeros((x1.shape[0], 3))
    
    cond = np.logical_and(x1 >= bin[0], x1 < bin[1]) & np.logical_and(x2 >= bin[0], x2 < bin[1])
    temp[cond, 0] = A + ((x1[cond] -bin[0])/(bin[1]-bin[0]))*(B-A)
    temp[cond, 1] = A + ((x2[cond] -bin[0])/(bin[1]-bin[0]))*(B-A)
    
    cond = np.logical_and(x1 >= bin[0], x1 < bin[1]) & np.logical_and(x2 >= bin[1], x2 < bin[2])
    temp[cond, 0] = A + ((x1[cond] -bin[0])/(bin[1]-bin[0]))*(B-A)
    temp[cond, 1] = B + ((x2[cond] -bin[1])/(bin[2]-bin[1]))*(C-B)
    
    cond = np.logical_and(x1 >= bin[0], x1 < bin[1]) & np.logical_and(x2 >= bin[2], x2 < bin[3])
    temp[cond, 0] = A + ((x1[cond] -bin[0])/(bin[1]-bin[0]))*(B-A)
    temp[cond, 1] = C + ((x2[cond] -bin[2])/(bin[3]-bin[2]))*(D-C)
    
    cond = np.logical_and(x1 >= bin[1], x1 < bin[2]) & np.logical_and(x2 >= bin[1], x2 < bin[2])
    temp[cond, 0] = B + ((x1[cond] -bin[1])/(bin[2]-bin[1]))*(C-B)
    temp[cond, 1] = B + ((x2[cond] -bin[1])/(bin[2]-bin[1]))*(C-B)
    
    cond = np.logical_and(x1 >= bin[1], x1 < bin[2]) & np.logical_and(x2 >= bin[2], x2 < bin[3])
    temp[cond, 0] = B + ((x1[cond] -bin[1])/(bin[2]-bin[1]))*(C-B)
    temp[cond, 1] = C + ((x2[cond] -bin[2])/(bin[3]-bin[2]))*(D-C)
    
    cond = np.logical_and(x1 >= bin[2], x1 < bin[3]) & np.logical_and(x2 >= bin[2], x2 < bin[3])
    temp[cond, 0] = C + ((x1[cond] -bin[2])/(bin[3]-bin[2]))*(D-C)
    temp[cond, 1] = C + ((x2[cond] -bin[2])/(bin[3]-bin[2]))*(D-C)

    temp[:,2] = np.divide(temp[:,0], temp[:,1])
            
    return (temp[:,2])

bin=[4,4.5,5,5.5]

y=interpo((x11, x22), 4.2, 0.9, 3.7, 11.0)

popt, pcov = curve_fit(interpo, (x11, x22), y, method='lm')

print(popt)
Related