2010-06-22 6 views
0

J'ai besoin de faire correspondre des points de différents ensembles de données avec des lignes droites. À partir de chaque ensemble de données, je veux ajuster une ligne. J'ai donc les paramètres ai et bi qui décrivent la i-line: ai + bi * x. Le problème est que je veux imposer que tous les ai sont égaux parce que je veux le même intercepte. J'ai trouvé un tutoriel ici: http://www.scipy.org/Cookbook/FittingData#head-a44b49d57cf0165300f765e8f1b011876776502f. La différence est que je ne connais pas le nombre de données que je possède. Mon code est le suivant:scipy smart optimize

from numpy import * 
from scipy import optimize 

# here I have 3 dataset, but in general I don't know how many dataset are they 
ypoints = [array([0, 2.1, 2.4]), # first dataset, 3 points 
      array([0.1, 2.1, 2.9]), # second dataset 
      array([-0.1, 1.4])]  # only 2 points 

xpoints = [array([0, 2, 2.5]),  # first dataset 
      array([0, 2, 3]),  # second, also x coordinates are different 
      array([0, 1.5])]   # the first coordinate is always 0 

fitfunc = lambda a, b, x: a + b * x 
errfunc = lambda p, xs, ys: array([ yi - fitfunc(p[0], p[i+1], xi) 
            for i, (xi,yi) in enumerate(zip(xs, ys)) ]) 


p_arrays = [r_[0.]] * len(xpoints) 
pinit = r_[[ypoints[0][0]] + p_arrays] 
fit_parameters, success = optimize.leastsq(errfunc, pinit, args = (xpoints, ypoints)) 

Je suis

Traceback (most recent call last): 
    File "prova.py", line 19, in <module> 
    fit_parameters, success = optimize.leastsq(errfunc, pinit, args = (xpoints, ypoints)) 
    File "/usr/lib64/python2.6/site-packages/scipy/optimize/minpack.py", line 266, in leastsq 
    m = check_func(func,x0,args,n)[0] 
    File "/usr/lib64/python2.6/site-packages/scipy/optimize/minpack.py", line 12, in check_func 
    res = atleast_1d(thefunc(*((x0[:numinputs],)+args))) 
    File "prova.py", line 14, in <lambda> 
    for i, (xi,yi) in enumerate(zip(xs, ys)) ]) 
ValueError: setting an array element with a sequence. 

Répondre

1

Si vous avez juste besoin d'un ajustement linéaire, alors il est préférable de l'estimer avec une régression linéaire au lieu d'un optimiseur non linéaire. D'autres statistiques d'ajustement pourraient être obtenues en utilisant plutôt scikits.statsmodels.

import numpy as np 
from numpy import array 

ypoints = np.r_[array([0, 2.1, 2.4]), # first dataset, 3 points 
      array([0.1, 2.1, 2.9]), # second dataset 
      array([-0.1, 1.4])]  # only 2 points 

xpoints = [array([0, 2, 2.5]),  # first dataset 
      array([0, 2, 3]),  # second, also x coordinates are different 
      array([0, 1.5])]   # the first coordinate is always 0 

xp = np.hstack(xpoints) 
indicator = [] 
for i,a in enumerate(xpoints): 
    indicator.extend([i]*len(a)) 

indicator = np.array(indicator) 


x = xp[:,None]*(indicator[:,None]==np.arange(3)).astype(int) 
x = np.hstack((np.ones((xp.shape[0],1)),x)) 

print np.dot(np.linalg.pinv(x), ypoints) 
# [ 0.01947973 0.98656987 0.98481549 0.92034684] 

La matrice de régresseurs a une intersection commune, mais des colonnes différentes pour chaque jeu de données:

>>> x 
array([[ 1. , 0. , 0. , 0. ], 
     [ 1. , 2. , 0. , 0. ], 
     [ 1. , 2.5, 0. , 0. ], 
     [ 1. , 0. , 0. , 0. ], 
     [ 1. , 0. , 2. , 0. ], 
     [ 1. , 0. , 3. , 0. ], 
     [ 1. , 0. , 0. , 0. ], 
     [ 1. , 0. , 0. , 1.5]]) 
+0

merci, j'aime ça. Le problème est que maintenant j'ai besoin d'utiliser des erreurs, je veux dire: y point avoir des erreurs, et j'ai besoin de les pondérer avec 1/erreur^2. Comment puis-je le faire avec votre code? –

+0

Le meilleur serait vraiment d'utiliser scikits.statsmodels parce que pour ce cas vous avez toutes les statistiques d'estimation, de prédiction et de résultat. http://pypi.python.org/pypi/scikits.statsmodels/0.2.0 et des liens pour obtenir prédits y params = np.dot (np.linalg.pinv (x), ypoints) ypred = np.dot (x, params) errors = ypoints - ypred ... Si vous voulez dire en pondérant les erreurs, pour utiliser les moindres carrés pondérés, les deux points x et y doivent être divisés par écart type d'erreur, ou utiliser Classe WLS dans scikits.statsmodels. – user333700

1

(Side note: utiliser def, non lambda attribué à un nom - qui est tout à fait stupide et n'a que des inconvénients, l'utilisation que de lambda fait anonyme fonctions!).

Votre errfunc doit retourner une séquence (tableau ou autre) de nombres à virgule flottante, mais ce n'est pas, parce que vous essayez de mettre les éléments de vos tableaux les tableaux qui sont les différences chaque point y (rappelez-vous, ypoints aka ys est une liste de tableaux!) et les résultats des fonctions d'ajustement. Vous devez donc "réduire" l'expression yi - fitfunc(p[0], p[i+1], xi) en un seul nombre à virgule flottante, par ex. norm(yi - fitfunc(p[0], p[i+1], xi)).

+0

Je ne peux pas comprendre les différences entre l'exemple dans le lien –

+0

@Wiso, ce code est assez obscure (avec un 'r_' non documenté, etc) mais je suis sûr qu'il finit par renvoyer d'errfunc une suite de nombres à virgule flottante, car c'est ce dont les docs ont besoin - vérifier avec un débogueur ou l'utiliser avec' print's pour vérifiez, si vous pouvez exécuter ce code avec succès vous-même (je ne peux pas - qu'est-ce que 'r_' ?!). –

+0

ok, j'ai résolu. Habituellement scipy est bien documenté, la fonction 'r_' ici: http://docs.scipy.org/doc/numpy/reference/generated/numpy.r_.html La solution est de changer' array' à 'concatenate' pour obtenir un tableau unique comme vous l'avez dit. En particulier j'ai eu les coefficients: '[0.01947973 0.98656987 0.98481549 0.92034684]' et ils semblent être corrige –