Ajuste de una matriz de datos en 3D a una función 1D con números o scipy

4 Actualmente estoy tratando de ajustar una gran cantidad de datos a una función sinusoidal. En el caso de que solo tenga un conjunto de datos (matriz 1D), scipy.optimize.curve_fit() funciona bien. Sin embargo, no permite una entrada de datos de dimensiones más altas si la función en sí es solo una dimensión hasta donde puedo ver. No quiero recorrer la matriz utilizando bucles, ya que funciona increíblemente lento en Python.

Mi código hasta ahora debería ser similar a esto:

 from scipy import optimize import numpy as np def f(x,p1,p2,p3,p4): return p1 + p2*np.sin(2*np.pi*p3*x + p4) #fit function def fit(data,guess): n = data.shape[0] leng = np.arange(n) param, pcov = optimize.curve_fit(f,leng,data,guess) return param, pcov 

donde los datos son una matriz tridimensional ( shape=(x,y,z) ) y me gustaría ajustar los data[:,a,b] de cada línea data[:,a,b] a la función, donde param es una matriz con forma (4,y,z) como salida. Por supuesto, para datos multidimensionales esto resulta en una

ValueError: operands could not be broadcast together with shapes (2100,2100) (5)

Tal vez haya una solución fácil para esto, pero no estoy seguro de cómo hacerlo. ¿Alguna sugerencia?

La búsqueda de una respuesta a mi pregunta fue bastante difícil ya que la mayoría de los temas con esas palabras clave se relacionan con la adaptación de funciones de dimensiones superiores.

El uso de np.apply_along_axis() resuelve su problema. Solo haz esto:

 func1d = lambda y, *args: optimize.curve_fit(f, xdata=x, ydata=y, *args)[0] #<-- [0] to get only popt param = np.apply_along_axis( func1d, axis=2, arr=data ) 

Vea el ejemplo a continuación:

 from scipy import optimize import numpy as np def f(x,p1,p2,p3,p4): return p1 + p2*np.sin(2*np.pi*p3*x + p4) sx = 50 # size x sy = 200 # size y sz = 100 # size z # creating the reference parameters tmp = np.empty((4,sy,sz)) tmp[0,:,:] = (1.2-0.8) * np.random.random_sample((sy,sz)) + 0.8 tmp[1,:,:] = (1.2-0.8) * np.random.random_sample((sy,sz)) + 0.8 tmp[2,:,:] = np.ones((sy,sz)) tmp[3,:,:] = np.ones((sy,sz))*np.pi/4 param_ref = np.empty((4,sy,sz,sx)) # param_ref in this shape will allow an for i in range(sx): # one-shot evaluation of f() to create param_ref[:,:,:,i] = tmp # the data sample # creating the data sample x = np.linspace(0,2*np.pi) factor = (1.1-0.9)*np.random.random_sample((sy,sz,sx))+0.9 data = f(x, *param_ref) * factor # the one-shot evalution is here # finding the adjusted parameters func1d = lambda y, *args: optimize.curve_fit(f, xdata=x, ydata=y, *args)[0] #<-- [0] to get only popt param = np.apply_along_axis( func1d, axis=2, arr=data )