onot
onot

Reputation: 3

Generation of 3-D array

I want to generate a 3-D array by assigning an array to an array.
Following are codes written by me.

import numpy as np
    def func01(a):
        b = np.array([[a, 3],
                      [4, 5]])
        return b
    
    a = np.array([1, 2]) 
    b = func01(a)
    print(b)

Originally, I wrote this code expecting the following output.

    [[[1 3]
      [4 5]]
     [[2 3]
      [4 5]]]

However, the following output is obtained.

    [[array([1, 2]) 3]
     [4 5]]

Could someone give me a solution?

My goal is to curve fit a function involving matrix calculation by SciPy.
I want to perform the curve fit for following function.

import numpy as np
import scipy.optimize

def func01(A, k):
    b1 = np.array([[A[0], 3],
                  [4, 5]])
    b2 = np.array([[A[1], 3],
                  [4, 5]])

    B = np.dot(b1, b2)    
    w, v = np.linalg.eig(B)
    C = w[np.argmax(w)] * k
    
    return C

x = np.array([173, 273, 373]) 
y = np.array([0.1, 0.2, 0.3])
xy = np.append([x],[y],axis=0)
z = np.array([0.023, 0.027, 0.031])
k =0.00005 # initial value
para_opt, cov = scipy.optimize.curve_fit(func01, xy, z, k)
print(para_opt[0])

I can get the value with a simple variable assignment in this function.

k = 0.0005
A = np.array([1,2])
C = func01(A, k)
print(C)

However, I cannot perform the curve fit with SciPy. When I used the SciPy, the following values were assigned to b1 above.

[[array([173., 273., 373.]) 3]
 [4 5]]

Therefore, I wanted to know how to get the following matrix.

[[[173 3]
  [4 5]]
 [[173 3]
  [4 5]]]
 [[173 3]
  [4 5]]]

Upvotes: 0

Views: 62

Answers (2)

Valdi_Bo
Valdi_Bo

Reputation: 31011

Try the following function:

def func01(a):
    n = len(a)
    b = np.tile(np.array([[0, 3], [4, 5]]), (n,1)).reshape(-1,2,2)
    b[:,0,0] = a
    return b

It gives proper results regardless of the length of a. Furthermore, a can be either a list or a 1-D Numpy array.

To test this function, run:

a = np.array([11, 12, 13])
func01(a)

getting:

array([[[11,  3],
        [ 4,  5]],

       [[12,  3],
        [ 4,  5]],

       [[13,  3],
        [ 4,  5]]])

Upvotes: 0

hpaulj
hpaulj

Reputation: 231738

In [210]: res = np.zeros((2,2,2),int)                                                                
In [211]: res[:] = np.array([[0,3],[4,5]])                                                           
In [212]: res                                                                                        
Out[212]: 
array([[[0, 3],
        [4, 5]],

       [[0, 3],
        [4, 5]]])
In [213]: res[:,0,0]=[1,2]                                                                           
In [214]: res                                                                                        
Out[214]: 
array([[[1, 3],
        [4, 5]],

       [[2, 3],
        [4, 5]]])

Tell us about curve_fit. What does it expect with regards to the arguments - type and shape? Do your arguments fit? As written your function expects A to have shape (2,). Is that what you are getting? Why, or why not?

(I could look up curve_fit docs, but I'd rather you did some that leg work. You need the debugging practice :)

your curve_fit problem - with column iteration

So your arrays are:

In [216]: xy                                                                                         
Out[216]: 
array([[1.73e+02, 2.73e+02, 3.73e+02],
       [1.00e-01, 2.00e-01, 3.00e-01]])
In [217]: z                                                                                          
Out[217]: array([0.023, 0.027, 0.031])

And apparently you want to call func01 with one column of xy:

In [219]: func01(xy[:,0],.00005)                                                                     
Out[219]: 0.00687966968797453

to work with all columns we can start with an straight forward iteration:

In [220]: def foo(A,k): 
     ...:     return np.array([func01(A[:,i],k) for i in range(A.shape[1])]) 

In [222]: foo(xy,.00005)                                                                             
Out[222]: array([0.00687967, 0.00921688, 0.0120737 ])

And using that in curve_fit:

In [223]: k =0.00005 # initial value     
In [226]: optimize.curve_fit(foo, xy, z, k)                                                          
Out[226]: (array([0.00014051]), array([[1.04449717e-10]]))

A further step is to modify the function so it works with 2d xy without that iteration. But for a start we need a clear working example. It's always easier to improve working code that we can check our answers against.

vectorizing func (part 1)

Now that we have reference we can try to "vectorize" the function - step by step. We need to do more than generate a 3d array, I think.

Looks like the b1.dot(b2) and following needs to be a "batched" operation, so lets use @:

In [228]: def func02(A, k): 
     ...:     bb = np.zeros((2,A.shape[1],2,2)) 
     ...:     for i in range(A.shape[1]): 
     ...:         bb[0,i] = np.array([[A[0,i], 3], 
     ...:                   [4, 5]]) 
     ...:         bb[1,i] = np.array([[A[1,i], 3], 
     ...:                   [4, 5]]) 
     ...:  
     ...:     #B = np.dot(b1, b2) 
     ...:     B = bb[0] @ bb[1]     
     ...:     w, v = np.linalg.eig(B) 
     ...:     C = w[np.argmax(w, axis=-1)] * k 
     ...:     return C 
     ...:                                                                                            

In [230]: func02(xy,.00005)                                                                          
Out[230]: 
array([[ 0.00921688, -0.00403688],
       [-0.00356467,  0.00687967],
       [-0.00356467,  0.00687967]])

Not right. Let's a shape print:

In [231]: def func02(A, k): 
     ...:     bb = np.zeros((2,A.shape[1],2,2)) 
     ...:     for i in range(A.shape[1]): 
     ...:         bb[0,i] = np.array([[A[0,i], 3], 
     ...:                   [4, 5]]) 
     ...:         bb[1,i] = np.array([[A[1,i], 3], 
     ...:                   [4, 5]]) 
     ...:  
     ...:     #B = np.dot(b1, b2) 
     ...:     B = bb[0] @ bb[1]     
     ...:     w, v = np.linalg.eig(B) 
     ...:     print(B.shape, w.shape) 
     ...:     C = w[np.argmax(w, axis=-1)] * k 
     ...:     return C 
     ...:      
     ...:                                                                                            
In [232]:                                                                                            
In [232]: func02(xy,.00005)                                                                          
(3, 2, 2) (3, 2)
Out[232]: 
array([[ 0.00921688, -0.00403688],
       [-0.00356467,  0.00687967],
       [-0.00356467,  0.00687967]])

The w indexing needs tweaking:

In [233]: def func02(A, k): 
     ...:     bb = np.zeros((2,A.shape[1],2,2)) 
     ...:     for i in range(A.shape[1]): 
     ...:         bb[0,i] = np.array([[A[0,i], 3], 
     ...:                   [4, 5]]) 
     ...:         bb[1,i] = np.array([[A[1,i], 3], 
     ...:                   [4, 5]]) 
     ...:  
     ...:     #B = np.dot(b1, b2) 
     ...:     B = bb[0] @ bb[1]     
     ...:     w, v = np.linalg.eig(B) 
     ...:     print(B.shape, w.shape) 
     ...:     C = w[:, np.argmax(w, axis=-1)] * k 
     ...:     return C 
     ...:      
     ...:                                                                                            
In [234]: func02(xy,.00005)                                                                          
(3, 2, 2) (3, 2)
Out[234]: 
array([[ 0.00687967, -0.00356467, -0.00356467],
       [-0.00403688,  0.00921688,  0.00921688],
       [-0.0040287 ,  0.0120737 ,  0.0120737 ]])

The correct values are on the diagonal, so we need another change to the indexing:

In [235]: def func02(A, k): 
     ...:     n = A.shape[1] 
     ...:     bb = np.zeros((2,n,2,2)) 
     ...:     for i in range(n): 
     ...:         bb[0,i] = np.array([[A[0,i], 3], 
     ...:                   [4, 5]]) 
     ...:         bb[1,i] = np.array([[A[1,i], 3], 
     ...:                   [4, 5]]) 
     ...:  
     ...:     #B = np.dot(b1, b2) 
     ...:     B = bb[0] @ bb[1]     
     ...:     w, v = np.linalg.eig(B) 
     ...:     print(B.shape, w.shape) 
     ...:     C = w[np.arange(n), np.argmax(w, axis=-1)] * k 
     ...:     return C 
     ...:      
     ...:                                                                                            
In [236]: func02(xy,.00005)                                                                          
(3, 2, 2) (3, 2)
Out[236]: array([0.00687967, 0.00921688, 0.0120737 ])

That matches foo. So works in the curvefit:

In [237]: optimize.curve_fit(func02, xy, z, k)                                                       
(3, 2, 2) (3, 2)
...
(3, 2, 2) (3, 2)
Out[237]: (array([0.00014051]), array([[1.04449717e-10]]))

Now that we have the last part of func02 right, we can address your original 3d array issue.

final

Using the array construction I started with:

In [240]: def func02(A, k): 
     ...:     n = A.shape[1] 
     ...:     bb = np.zeros((2,n,2,2)) 
     ...:     bb[:] = np.array([[0,3],[4,5]]) 
     ...:     bb[:,:,0,0] = A 
     ...:     B = bb[0] @ bb[1]     
     ...:     w, v = np.linalg.eig(B) 
     ...:     C = w[np.arange(n), np.argmax(w, axis=-1)] * k 
     ...:     return C 
     ...:                                                                                            
In [241]: func02(xy,.00005)                                                                          
Out[241]: array([0.00687967, 0.00921688, 0.0120737 ])

Upvotes: 1

Related Questions