Bölümlenmiş regresyon için Python kütüphanesi (parçalı regresyon olarak da bilinir)


16

Segmentli regresyon (parçalı regresyon olarak da bilinir) gerçekleştirebilen bir Python kütüphanesi arıyorum .

Örnek :

resim açıklamasını buraya girin



Bu soru, bir işlevi tanımlayarak ve standart python kitaplıkları kullanarak parçalı regresyon gerçekleştirmek için bir yöntem verir. stackoverflow.com/questions/29382903/…

Benzer bir soru ( stackoverflow.com/questions/29382903/… ) ve parçalı regresyon için yararlı bir kütüphane ( pypi.org/project/pwlf )
prashanth

Yanıtlar:


7

numpy.piecewise bunu yapabilirsin.

parçalı parça (x, iletken listesi, işlev listesi, * argümanlar, ** kw)

Parçalı tanımlı bir işlevi değerlendirin.

Bir dizi koşul ve karşılık gelen işlevler verildiğinde, giriş verileri üzerindeki her bir işlevi, durumunun doğru olduğu her yerde değerlendirin.

Burada SO üzerinde bir örnek verilmiştir . Bütünlük için, bir örnek:

from scipy import optimize
import matplotlib.pyplot as plt
import numpy as np

x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ,11, 12, 13, 14, 15], dtype=float)
y = np.array([5, 7, 9, 11, 13, 15, 28.92, 42.81, 56.7, 70.59, 84.47, 98.36, 112.25, 126.14, 140.03])

def piecewise_linear(x, x0, y0, k1, k2):
    return np.piecewise(x, [x < x0, x >= x0], [lambda x:k1*x + y0-k1*x0, lambda x:k2*x + y0-k2*x0])

p , e = optimize.curve_fit(piecewise_linear, x, y)
xd = np.linspace(0, 15, 100)
plt.plot(x, y, "o")
plt.plot(xd, piecewise_linear(xd, *p))

4

Vito MR Muggeo [1] tarafından önerilen yöntem nispeten basit ve etkilidir. Belirli sayıda segment ve sürekli işlev için çalışır. Kesme noktalarının konumları, her yineleme için kesme noktalarında sıçramalara izin veren bölümlere ayrılmış bir doğrusal regresyon gerçekleştirilerek yinelemeli olarak tahmin edilir. Atlamaların değerlerinden, daha fazla süreksizlik (atlamalar) kalmayana kadar bir sonraki kesme noktası konumları çıkarılır.

"süreç, genel olarak garanti edilmeyen olası yakınsamaya kadar yinelenir"

Özellikle yakınsama veya sonuç, kesme noktalarının ilk tahminine bağlı olabilir.

Bu, R Segment paketinde kullanılan yöntemdir .

İşte python bir uygulama:

import numpy as np
from numpy.linalg import lstsq

ramp = lambda u: np.maximum( u, 0 )
step = lambda u: ( u > 0 ).astype(float)

def SegmentedLinearReg( X, Y, breakpoints ):
    nIterationMax = 10

    breakpoints = np.sort( np.array(breakpoints) )

    dt = np.min( np.diff(X) )
    ones = np.ones_like(X)

    for i in range( nIterationMax ):
        # Linear regression:  solve A*p = Y
        Rk = [ramp( X - xk ) for xk in breakpoints ]
        Sk = [step( X - xk ) for xk in breakpoints ]
        A = np.array([ ones, X ] + Rk + Sk )
        p =  lstsq(A.transpose(), Y, rcond=None)[0] 

        # Parameters identification:
        a, b = p[0:2]
        ck = p[ 2:2+len(breakpoints) ]
        dk = p[ 2+len(breakpoints): ]

        # Estimation of the next break-points:
        newBreakpoints = breakpoints - dk/ck 

        # Stop condition
        if np.max(np.abs(newBreakpoints - breakpoints)) < dt/5:
            break

        breakpoints = newBreakpoints
    else:
        print( 'maximum iteration reached' )

    # Compute the final segmented fit:
    Xsolution = np.insert( np.append( breakpoints, max(X) ), 0, min(X) )
    ones =  np.ones_like(Xsolution) 
    Rk = [ c*ramp( Xsolution - x0 ) for x0, c in zip(breakpoints, ck) ]

    Ysolution = a*ones + b*Xsolution + np.sum( Rk, axis=0 )

    return Xsolution, Ysolution

Misal:

import matplotlib.pyplot as plt

X = np.linspace( 0, 10, 27 )
Y = 0.2*X  - 0.3* ramp(X-2) + 0.3*ramp(X-6) + 0.05*np.random.randn(len(X))
plt.plot( X, Y, 'ok' );

initialBreakpoints = [1, 7]
plt.plot( *SegmentedLinearReg( X, Y, initialBreakpoints ), '-r' );
plt.xlabel('X'); plt.ylabel('Y');

grafik

[1]: Muggeo, VM (2003). Bilinmeyen sınır değerleri olan regresyon modellerini tahmin etmek. Tıpta istatistik, 22 (19), 3055-3071.


3

Aynı şeyi arıyordum ve maalesef şu anda bir tane yok gibi görünüyor. Nasıl ilerleyeceğinize dair bazı öneriler bu önceki soruda bulunabilir .

Alternatif olarak segmentlere ayrılmış, SiZer, strucchange gibi bazı R kitaplıklarına bakabilirsiniz ve orada bir şey işe yararsa R kodunu rpy2 ile python'a gömmeyi deneyin .

Py-earth'e bir bağlantı eklemek için düzenleme yapan "Jerome Friedman'ın Çok Değişkenli Uyarlanabilir Regresyon Spline'larının bir Python uygulaması".


2

Parçalı regresyonun özyinelemeli bir uygulaması olan bir blog yazısı var. Bu çözüm süreksiz regresyona uyar.

Süreksiz modelden memnun değilseniz ve sürekli ayar yapmak istiyorsanız, eğrinizi kL-şekilli eğriler temelinde aramayı ve azlık için Kement'i kullanmayı öneriyorum :

import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import Lasso
# generate data
np.random.seed(42)
x = np.sort(np.random.normal(size=100))
y_expected = 3 + 0.5 * x + 1.25 * x * (x>0)
y = y_expected + np.random.normal(size=x.size, scale=0.5)
# prepare a basis
k = 10
thresholds = np.percentile(x, np.linspace(0, 1, k+2)[1:-1]*100)
basis = np.hstack([x[:, np.newaxis],  np.maximum(0,  np.column_stack([x]*k)-thresholds)]) 
# fit a model
model = Lasso(0.03).fit(basis, y)
print(model.intercept_)
print(model.coef_.round(3))
plt.scatter(x, y)
plt.plot(x, y_expected, color = 'b')
plt.plot(x, model.predict(basis), color='k')
plt.legend(['true', 'predicted'])
plt.xlabel('x')
plt.ylabel('y')
plt.title('fitting segmented regression')
plt.show()

Bu kod size tahmini katsayıların bir vektörünü döndürür:

[ 0.57   0.     0.     0.     0.     0.825  0.     0.     0.     0.     0.   ]

Kement yaklaşımı nedeniyle, seyrek: model olası 10 arasında tam bir kırılma noktası buldu. 0.57 ve 0.825 sayıları gerçek DGP'de 0.5 ve 1.25'e karşılık gelir. Çok yakın olmasalar da, takılan eğriler:

resim açıklamasını buraya girin

Bu yaklaşım, kesme noktasını tam olarak tahmin etmenize izin vermez. Ancak veri kümeniz yeterince büyükse, farklı biriyle oynayabilir k(belki de çapraz doğrulamayla ayarlayabilirsiniz) ve kesme noktasını tam olarak tahmin edebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.