簡體   English   中英

為什么statsmodels的OLS中的四次線性回歸不匹配LibreOffice Calc?

[英]Why doesn't a quartic linear regression in statsmodels' OLS match LibreOffice Calc?

我將Statsmodels的OLS線性回歸與Patsy四次公式y〜x y ~ x + I(x**2) + I(x**3) + I(x**4)但所得回歸結果與擬合的數據相差甚遠到LibreOffice Calc。 為什么這與LibreOffice Calc產生的結果不匹配?

statsmodels代碼:

import io
import numpy
import pandas
import matplotlib
import matplotlib.offsetbox
import statsmodels.tools
import statsmodels.formula.api

csv_data = """Year,CrudeRate
1999,197.0
2000,196.5
2001,194.3
2002,193.7
2003,192.0
2004,189.2
2005,189.3
2006,187.6
2007,186.9
2008,186.0
2009,185.0
2010,186.2
2011,185.1
2012,185.6
2013,185.0
2014,185.6
2015,185.4
2016,185.1
2017,183.9
"""

df = pandas.read_csv(io.StringIO(csv_data))

cause = "Malignant neoplasms"
x = df["Year"].values
y = df["CrudeRate"].values

olsdata = {"x": x, "y": y}
formula = "y ~ x + I(x**2) + I(x**3) + I(x**4)"
model = statsmodels.formula.api.ols(formula, olsdata).fit()

print(model.params)

df.plot("Year", "CrudeRate", kind="scatter", grid=True, title="Deaths from {}".format(cause))

func = numpy.poly1d(model.params.values[::-1])
matplotlib.pyplot.plot(df["Year"], func(df["Year"]))

matplotlib.pyplot.show()

產生以下系數:

Intercept    9.091650e-08
x            9.127904e-05
I(x ** 2)    6.109623e-02
I(x ** 3)   -6.059164e-05
I(x ** 4)    1.503399e-08

和下圖:

圖1

但是,如果我將數據帶入LibreOffice Calc,請單擊圖並選擇“插入趨勢線...”,選擇“多項式”,輸入“度數” = 4,然后選擇“顯示方程式”,結果趨勢線為與statsmodels不同,並且看起來更合適:

圖2

系數為:

Intercept = 1.35e10
x =          2.69e7
x^2 =       -2.01e4
x^3 =          6.69
x^4 =      -0.83e-3

statsmodels版本:

$ pip3 list | grep statsmodels
statsmodels                  0.9.0

編輯:三次也不匹配,但是二次匹配。

編輯:按比例縮小Year (並在LibreOffice中執行相同操作)匹配項:

df = pandas.read_csv(io.StringIO(csv_data))
df["Year"] = df["Year"] - 1998

縮小后的系數和圖:

Intercept    197.762384
x             -0.311548
I(x ** 2)     -0.315944
I(x ** 3)      0.031304
I(x ** 4)     -0.000833

圖3

根據@Josef的評論,問題在於大量數字不適用於高階多項式,而statsmodels不能自動縮放域。 此外,我在原始問題中沒有提到這一點,因為我不希望對域進行轉換,但是我還需要根據年份來預測樣本外值,因此我將其設為范圍的結尾:

predict_x = +5
min_scaled_domain = -1
max_scaled_domain = +1
df["Year"] = df["Year"].transform(lambda x: numpy.interp(x, (x.min(), x.max() + predict_x), (min_scaled_domain, max_scaled_domain)))

此轉換創建了擬合良好的回歸:

圖4

如果在LibreOffice Calc中應用了相同的域轉換,則系數匹配。

最后,打印預測值:

func = numpy.polynomial.Polynomial(model.params)
print(func(max_scaled_domain))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM