2012-04-03 11 views
14

Ich bin ein bisschen von einem Newby so Entschuldigungen, wenn diese Frage bereits beantwortet wurde, habe ich einen Blick und konnte nicht speziell finden, was ich suchte.Wie erzwinge Nullabfangen in der linearen Regression?

Ich habe einige mehr oder weniger lineare Daten des Formulars

x = [0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 2.0, 4.0, 6.0, 8.0, 10.0, 20.0, 40.0, 60.0, 80.0] 
y = [0.50505332505407008, 1.1207373784533172, 2.1981844719020001, 3.1746209003398689, 4.2905482471260044, 6.2816226678076958, 11.073788414382639, 23.248479770546009, 32.120462301367183, 44.036117671229206, 54.009003143831116, 102.7077685684846, 185.72880217806673, 256.12183145545811, 301.97120103079675] 

I scipy.optimize.leastsq bin mit einer linearen Regression auf diese passen:

def lin_fit(x, y): 
    '''Fits a linear fit of the form mx+b to the data''' 
    fitfunc = lambda params, x: params[0] * x + params[1] #create fitting function of form mx+b 
    errfunc = lambda p, x, y: fitfunc(p, x) - y    #create error function for least squares fit 

    init_a = 0.5       #find initial value for a (gradient) 
    init_b = min(y)       #find initial value for b (y axis intersection) 
    init_p = numpy.array((init_a, init_b)) #bundle initial values in initial parameters 

    #calculate best fitting parameters (i.e. m and b) using the error function 
    p1, success = scipy.optimize.leastsq(errfunc, init_p.copy(), args = (x, y)) 
    f = fitfunc(p1, x)   #create a fit with those parameters 
    return p1, f  

Und es funktioniert wunderbar (obwohl ich nicht bin sicher, wenn scipy.optimize ist das richtige, hier zu verwenden, könnte es ein wenig übertrieben sein?).

Aufgrund der Art und Weise, wie die Datenpunkte liegen, gibt es mir jedoch keine Y-Achsenüberwachung bei 0. Ich weiß jedoch, dass es in diesem Fall 0 sein muss, if x = 0 than y = 0.

Gibt es eine Möglichkeit, dies zu erzwingen?

+0

Wenn Sie wissen, dass Ihr Intercept 0 ist, warum haben Sie es als freier Parameter in Ihrer Funktion zu passen? Könnten Sie "b" einfach als freien Parameter entfernen? – Jdog

+0

Ah. Ja. Na sicher! Ich entschuldige mich, das ist eine wirklich offensichtliche Antwort. Manchmal sehe ich den Wald nicht für die Bäume: - Das geht gut. Vielen Dank, dass du es mir gezeigt hast! –

+0

Ich sehe nur die Handlung der Daten in einer Antwort. Unabhängig von der Frage sollten Sie versuchen, ein Polynom zweiter Ordnung zu verwenden. Normalerweise kann man sagen, dass der Achsenabschnitt null ist, wenn er in der Reihenfolge seines Fehlers ist, und ich denke, dass in einer Parabel passen Sie es bekommen. – chuse

Antwort

9

Ich bin nicht geschickt in diesen Modulen, aber ich habe einige Erfahrung in Statistiken, also hier ist, was ich sehe. Sie benötigen eine Fit-Funktion von

fitfunc = lambda params, x: params[0] * x + params[1] 

zu ändern:

fitfunc = lambda params, x: params[0] * x 

Entfernen Sie auch die Zeile:

init_b = min(y) 

und ändern Sie die nächste Zeile:

init_p = numpy.array((init_a)) 

Dies sollte den zweiten Parameter loswerden Das erzeugt den y-Achsenabschnitt und führt die angepasste Linie durch den Ursprung. Es könnte ein paar kleinere Änderungen geben, die Sie für den Rest Ihres Codes vornehmen müssen.

Aber ja, ich bin mir nicht sicher, ob dieses Modul funktioniert, wenn Sie den zweiten Parameter einfach so wegnehmen. Es hängt von den internen Abläufen des Moduls ab, ob es diese Änderung akzeptieren kann. Zum Beispiel weiß ich nicht, wo params, die Liste der Parameter, wird initialisiert, so dass ich nicht weiß, ob gerade dies seine Länge ändern wird.

Und als Nebenbemerkung, da Sie erwähnt haben, denke ich, dass dies tatsächlich ein wenig übertrieben ist, um nur eine Steigung zu optimieren. Sie könnten lineare Regression ein wenig lesen und kleinen Code schreiben, um es selbst nach etwas Back-of-the-Envelope-Kalkül zu tun. Es ist ziemlich einfach und aufrichtig, wirklich. Tatsächlich habe ich nur einige Berechnungen durchgeführt, und ich nehme an, dass die optimierte Steigung einfach <xy>/<x^2> ist, d. H. Der Mittelwert von x * y-Produkten dividiert durch den Mittelwert von x^2-Werten.

+0

Danke, das ist genau das, was ich tun muss. :) –

+0

In der Tat ist die richtige Lösung für die Anpassung der kleinsten Quadrate von 'y = a * x' nur 'a = x.dot (y)/x.dot (x)' wie Abhranil nahe dem Ende schrieb. – divenex

26

Als @AbhranilDas erwähnt, verwenden Sie einfach eine lineare Methode. Ein nichtlinearer Löser wie ist nicht erforderlich.

Normalerweise würden Sie numpy.polyfit verwenden, um eine Zeile an Ihre Daten anzupassen, aber in diesem Fall müssen Sie numpy.linalg.lstsq direkt verwenden, um den Schnittpunkt auf Null zu setzen.

Als kleines Beispiel:

import numpy as np 
import matplotlib.pyplot as plt 

x = np.array([0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 2.0, 4.0, 6.0, 8.0, 10.0, 
       20.0, 40.0, 60.0, 80.0]) 

y = np.array([0.50505332505407008, 1.1207373784533172, 2.1981844719020001, 
       3.1746209003398689, 4.2905482471260044, 6.2816226678076958, 
       11.073788414382639, 23.248479770546009, 32.120462301367183, 
       44.036117671229206, 54.009003143831116, 102.7077685684846, 
       185.72880217806673, 256.12183145545811, 301.97120103079675]) 

# Our model is y = a * x, so things are quite simple, in this case... 
# x needs to be a column vector instead of a 1D vector for this, however. 
x = x[:,np.newaxis] 
a, _, _, _ = np.linalg.lstsq(x, y) 

plt.plot(x, y, 'bo') 
plt.plot(x, a*x, 'r-') 
plt.show() 

enter image description here

+0

Danke. Das war die Antwort, nach der ich suchte. Ich fand ein weiteres Beispiel dafür, wie man 'linalg.lstsq' mit einem Intercept in meinem allgemeinen Verständnis verwendet. Ersetzen Sie dazu 'x = x [:, np.newaxis]' durch 'x = np.vstack ([x, np.ones (len (x))])) – Snorfalorpagus

Verwandte Themen