2016-11-04 5 views
2

일부 데이터에 표면 방정식을 맞추고 싶습니다. scipy.optimize.leastsq를 이미 시도했지만 경계를 지정할 수 없기 때문에 사용할 수없는 결과가납니다. 또한 scipy.optimize.least_squares을 시도했지만 그것은 나에게 오류 제공 :최소한의 사각형이 파이썬에서 3d 표면에 맞습니다.

ValueError: too many values to unpack 

내 방정식은 다음과 같습니다 방정식이 위와 같이 될 수 있도록

f(x,y,z)=(x-A+y-B)/2+sqrt(((x-A-y+B)/2)^2+C*z^2) 

매개 변수는 A, B, C가 발견되어야한다 다음 사항은 X, Y, Z에 사용되는 경우 0에 가까울 가능한 :

[ 
    [-0.071, -0.85, 0.401], 
    [-0.138, -1.111, 0.494], 
    [-0.317, -0.317, -0.317], 
    [-0.351, -2.048, 0.848] 
    ] 

경계는 A> 0, B> 0, C> 1

,745 것

나는 어떻게 그런 착용감을 얻어야합니까? 파이썬에서 가장 좋은 도구는 무엇입니까? 3D 표면을 맞추는 방법에 대한 예제를 검색했지만 함수 피팅을 포함하는 대부분의 예제는 선 또는 평평한 표면 맞춤에 관한 것입니다.

답변

5

나는이 문제를 scipy의 일반적인 optimize.minimize 메서드와 scipy의 optimize.least_squares 메서드로 어떻게 해결할 수 있는지에 대한보다 일반적인 예를 제공하기 위해이 대답을 편집했습니다.


먼저 문제를 설정할 수 있습니다 :

import numpy as np 
import scipy.optimize 

# =============================================== 
# SETUP: define common compoments of the problem 


def our_function(coeff, data): 
    """ 
    The function we care to optimize. 

    Args: 
     coeff (np.ndarray): are the parameters that we care to optimize. 
     data (np.ndarray): the input data 
    """ 
    A, B, C = coeff 
    x, y, z = data.T 
    return (x - A + y - B)/2 + np.sqrt(((x - A - y + B)/2) ** 2 + C * z ** 2) 


# Define some training data 
data = np.array([ 
    [-0.071, -0.85, 0.401], 
    [-0.138, -1.111, 0.494], 
    [-0.317, -0.317, -0.317], 
    [-0.351, -2.048, 0.848] 
]) 
# Define training target 
# This is what we want the target function to be equal to 
target = 0 

# Make an initial guess as to the parameters 
# either a constant or random guess is typically fine 
num_coeff = 3 
coeff_0 = np.ones(num_coeff) 
# coeff_0 = np.random.rand(num_coeff) 

이 엄격 최소 제곱,하지만 어떻게 이런 일에 대해 무엇입니까? 이 솔루션은 문제에 썰매 망치를 던지는 것과 같습니다. SVD 솔버를 사용하여 솔루션을보다 효율적으로 얻으려면 최소 제곱을 사용하는 방법이있을 수 있지만, 단지 답을 찾고 있다면 scipy.optimize.minimize가 당신을 찾을 것입니다.

# =============================================== 
# FORMULATION #1: a general minimization problem 

# Here the bounds and error are all specified within the general objective function 
def general_objective(coeff, data, target): 
    """ 
    General function that simply returns a value to be minimized. 
    The coeff will be modified to minimize whatever the output of this function 
    may be. 
    """ 
    # Constraints to keep coeff above 0 
    if np.any(coeff < 0): 
     # If any constraint is violated return infinity 
     return np.inf 
    # The function we care about 
    prediction = our_function(coeff, data) 
    # (optional) L2 regularization to keep coeff small 
    # (optional) reg_amount = 0.0 
    # (optional) reg = reg_amount * np.sqrt((coeff ** 2).sum()) 
    losses = (prediction - target) ** 2 
    # (optional) losses += reg 
    # Return the average squared error 
    loss = losses.sum() 
    return loss 


general_result = scipy.optimize.minimize(general_objective, coeff_0, 
             method='Nelder-Mead', 
             args=(data, target)) 
# Test what the squared error of the returned result is 
coeff = general_result.x 
general_output = our_function(coeff, data) 
print('====================') 
print('general_result =\n%s' % (general_result,)) 
print('---------------------') 
print('general_output = %r' % (general_output,)) 
print('====================') 

출력은 다음과 같습니다

==================== 
general_result = 
final_simplex: (array([[ 2.45700466e-01, 7.93719271e-09, 1.71257109e+00], 
     [ 2.45692680e-01, 3.31991619e-08, 1.71255150e+00], 
     [ 2.45726858e-01, 6.52636219e-08, 1.71263360e+00], 
     [ 2.45713989e-01, 8.06971686e-08, 1.71260234e+00]]), array([ 0.00012404, 0.00012404, 0.00012404, 0.00012404])) 
      fun: 0.00012404137498459109 
     message: 'Optimization terminated successfully.' 
      nfev: 431 
      nit: 240 
     status: 0 
     success: True 
      x: array([ 2.45700466e-01, 7.93719271e-09, 1.71257109e+00]) 
--------------------- 
general_output = array([ 0.00527974, -0.00561568, -0.00719941, 0.00357748]) 
==================== 

내가 당신이 할 필요가 실제 최소 제곱이 적응하기 위해 문서에서 발견 된 잔차를 계산하는 기능을 지정합니다 .

# =============================================== 
# FORMULATION #2: a special least squares problem 

# Here all that is needeed is a function that computes the vector of residuals 
# the optimization function takes care of the rest 
def least_squares_residuals(coeff, data, target): 
    """ 
    Function that returns the vector of residuals between the predicted values 
    and the target value. Here we want each predicted value to be close to zero 
    """ 
    A, B, C = coeff 
    x, y, z = data.T 
    prediction = our_function(coeff, data) 
    vector_of_residuals = (prediction - target) 
    return vector_of_residuals 


# Here the bounds are specified in the optimization call 
bound_gt = np.full(shape=num_coeff, fill_value=0, dtype=np.float) 
bound_lt = np.full(shape=num_coeff, fill_value=np.inf, dtype=np.float) 
bounds = (bound_gt, bound_lt) 

lst_sqrs_result = scipy.optimize.least_squares(least_squares_residuals, coeff_0, 
               args=(data, target), bounds=bounds) 
# Test what the squared error of the returned result is 
coeff = lst_sqrs_result.x 
lst_sqrs_output = our_function(coeff, data) 
print('====================') 
print('lst_sqrs_result =\n%s' % (lst_sqrs_result,)) 
print('---------------------') 
print('lst_sqrs_output = %r' % (lst_sqrs_output,)) 
print('====================') 

출력은 여기에 있습니다 : 당신이 쓴

==================== 
lst_sqrs_result = 
active_mask: array([ 0, -1, 0]) 
     cost: 6.197329866927735e-05 
     fun: array([ 0.00518416, -0.00564099, -0.00710112, 0.00385024]) 
     grad: array([ -4.61826888e-09, 3.70771396e-03, 1.26659198e-09]) 
     jac: array([[-0.72611025, -0.27388975, 0.13653112], 
     [-0.74479565, -0.25520435, 0.1644325 ], 
     [-0.35777232, -0.64222767, 0.11601263], 
     [-0.77338046, -0.22661953, 0.27104366]]) 
    message: '`gtol` termination condition is satisfied.' 
     nfev: 13 
     njev: 13 
    optimality: 4.6182688779976278e-09 
     status: 1 
    success: True 
      x: array([ 2.46392438e-01, 5.39025298e-17, 1.71555150e+00]) 
--------------------- 
lst_sqrs_output = array([ 0.00518416, -0.00564099, -0.00710112, 0.00385024]) 
==================== 
+0

코드는 나에게 정확한 결과를 제공! 그러나 나는 경계 조건을 어떻게 부과했는지 정말로 모르겠다. – UN4

+0

나는 그 일을 잊어 버렸다. ¯ \\ _ (ツ) _/¯. 처음에는 추측 한 값이 양수 값을 사용하고 L2 정규화로 인해 계수가 축소되어 좋은 응답을 얻었을 때 막 중단 되었기 때문에 효과가 있다고 생각합니다. 이 방법은 꽤 일반적이지만 if np.any (coeff <0) : return np.inf를 포함하면 제약 조건을 부과 할 수 있습니다. – Erotemic

+0

아, 알았어요. 감사! – UN4