Thư viện Python cho hồi quy phân đoạn (còn gọi là hồi quy piecewise)


16

Tôi đang tìm kiếm một thư viện Python có thể thực hiện hồi quy phân đoạn (hay còn gọi là hồi quy piecewise) .

Ví dụ :

nhập mô tả hình ảnh ở đây



Câu hỏi này đưa ra một phương pháp để thực hiện hồi quy piecewise bằng cách xác định hàm và sử dụng các thư viện python tiêu chuẩn. stackoverflow.com/questions/29382903/

Một câu hỏi tương tự ( stackoverflow.com/questions/29382903/, ) và một thư viện hữu ích cho hồi quy từng phần ( pypi.org/project/pwlf )
prashanth

Câu trả lời:


7

numpy.piecewise có thể làm điều này

piecewise (x, condlist, funclist, * args, ** kw)

Đánh giá một chức năng xác định từng phần.

Đưa ra một tập hợp các điều kiện và các hàm tương ứng, đánh giá từng hàm trên dữ liệu đầu vào bất cứ nơi nào điều kiện của nó là đúng.

Một ví dụ được đưa ra trên SO ở đây . Để hoàn thiện, đây là một ví dụ:

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

Phương pháp được đề xuất bởi Vito MR Muggeo [1] tương đối đơn giản và hiệu quả. Nó hoạt động cho một số phân đoạn được chỉ định và cho một chức năng liên tục. Vị trí của các điểm dừng được ước tính lặp lại bằng cách thực hiện, với mỗi lần lặp, một hồi quy tuyến tính được phân đoạn cho phép nhảy tại các điểm dừng. Từ các giá trị của bước nhảy, các vị trí điểm dừng tiếp theo được suy ra, cho đến khi không còn sự gián đoạn nữa (bước nhảy).

"quá trình được lặp đi lặp lại cho đến khi hội tụ có thể, nói chung, không được bảo đảm"

Cụ thể, sự hội tụ hoặc kết quả có thể phụ thuộc vào ước tính đầu tiên của các điểm dừng.

Đây là phương pháp được sử dụng trong gói R Segmented .

Đây là một triển khai trong python:

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

Thí dụ:

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');

đồ thị

[1]: Muggeo, VM (2003). Ước tính mô hình hồi quy với các điểm dừng chưa biết. Thống kê trong y học, 22 (19), 3055-3071.


3

Tôi đã tìm kiếm điều tương tự, và thật không may là dường như không có gì vào lúc này. Một số gợi ý về cách tiến hành có thể được tìm thấy trong câu hỏi trước đây .

Ngoài ra, bạn có thể xem xét một số thư viện R, ví dụ như phân đoạn, SiZer, strucchange và nếu có gì đó phù hợp với bạn, hãy thử nhúng mã R trong python với rpy2 .

Chỉnh sửa để thêm một liên kết đến py-earth , "Một triển khai Python của Splome Hồi quy thích ứng đa biến của Jerome Friedman".


2

Có một bài viết trên blog với việc thực hiện đệ quy hồi quy piecewise. Giải pháp đó phù hợp với hồi quy không liên tục.

Nếu bạn không hài lòng với mô hình không liên tục và muốn thiết lập liên tục, tôi sẽ đề xuất tìm đường cong của bạn trên cơ sở các kđường cong hình chữ L, sử dụng Lasso cho độ thưa thớt:

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()

Mã này sẽ trả về một vectơ hệ số ước tính cho bạn:

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

Do cách tiếp cận của Lasso, nó rất thưa thớt: mô hình tìm thấy chính xác một điểm dừng trong số 10 điểm có thể. Các số 0,57 và 0,825 tương ứng với 0,5 và 1,25 trong DGP thực. Mặc dù chúng không gần lắm, nhưng các đường cong được trang bị là:

nhập mô tả hình ảnh ở đây

Cách tiếp cận này không cho phép bạn ước tính điểm dừng chính xác. Nhưng nếu tập dữ liệu của bạn đủ lớn, bạn có thể chơi với khác nhau k(có thể điều chỉnh nó bằng cách xác thực chéo) và ước tính điểm dừng đủ chính xác.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.