statsmodel OLS 和 scikit-learn 线性回归的区别
Difference between statsmodel OLS and scikit-learn linear regression
我尝试用 iris 数据集练习线性回归模型。
from sklearn import datasets
import seaborn as sns
import pandas as pd
import statsmodels.api as sm
import statsmodels.formula.api as smf
from sklearn.linear_model import LinearRegression
# load iris data
train = sns.load_dataset('iris')
train
# one-hot-encoding
species_encoded = pd.get_dummies(train["species"], prefix = "speceis")
species_encoded
train = pd.concat([train, species_encoded], axis = 1)
train
# Split by feature and target
feature = ["sepal_length", "petal_length", "speceis_setosa", "speceis_versicolor", "speceis_virginica"]
target = ["petal_width"]
X_train = train[feature]
y_train = train[target]
案例 1:统计模型
# model
X_train_constant = sm.add_constant(X_train)
model = sm.OLS(y_train, X_train_constant).fit()
print("const : {:.6f}".format(model.params[0]))
print(model.params[1:])
result :
const : 0.253251
sepal_length -0.001693
petal_length 0.231921
speceis_setosa -0.337843
speceis_versicolor 0.094816
speceis_virginica 0.496278
案例 2:scikit-learn
# model
model = LinearRegression()
model.fit(X_train, y_train)
print("const : {:.6f}".format(model.intercept_[0]))
print(pd.Series(model.coef_[0], model.feature_names_in_))
result :
const : 0.337668
sepal_length -0.001693
petal_length 0.231921
speceis_setosa -0.422260
speceis_versicolor 0.010399
speceis_virginica 0.411861
为什么statsmodels和sklearn的结果不一样?
此外,除了全部或部分one-hot-encoded特征外,两个模型的结果是相同的。
您包括了一整套单热编码虚拟变量作为回归量,这导致线性组合等于常数,因此您具有完美的多重共线性:您的协方差矩阵是奇异的,您不能将其逆.
在幕后 statsmodels
和 sklearn
都依赖于 Moore-Penrose 伪逆并且可以很好地反转奇异矩阵,问题是在奇异协方差矩阵情况下获得的系数不意味着任何物理意义上的任何东西。包之间的实现略有不同(sklearn
依赖于 scipy.stats.lstsq
,statsmodels
有一些自定义过程 statsmodels.tools.pinv_extended
,基本上是 numpy.linalg.svd
,变化很小),所以在一天结束时,它们都显示 «nonsense»(因为无法获得有意义的系数),这只是设计选择显示哪种 «nonsense»。
如果取one-hot encoded dummy的系数之和,可以看到statsmodels
等于常数,sklearn
等于0,而该常量不同于 statsmodels
常量。不对完全多重共线性“负责”的变量系数不受影响。
我尝试用 iris 数据集练习线性回归模型。
from sklearn import datasets
import seaborn as sns
import pandas as pd
import statsmodels.api as sm
import statsmodels.formula.api as smf
from sklearn.linear_model import LinearRegression
# load iris data
train = sns.load_dataset('iris')
train
# one-hot-encoding
species_encoded = pd.get_dummies(train["species"], prefix = "speceis")
species_encoded
train = pd.concat([train, species_encoded], axis = 1)
train
# Split by feature and target
feature = ["sepal_length", "petal_length", "speceis_setosa", "speceis_versicolor", "speceis_virginica"]
target = ["petal_width"]
X_train = train[feature]
y_train = train[target]
案例 1:统计模型
# model
X_train_constant = sm.add_constant(X_train)
model = sm.OLS(y_train, X_train_constant).fit()
print("const : {:.6f}".format(model.params[0]))
print(model.params[1:])
result :
const : 0.253251
sepal_length -0.001693
petal_length 0.231921
speceis_setosa -0.337843
speceis_versicolor 0.094816
speceis_virginica 0.496278
案例 2:scikit-learn
# model
model = LinearRegression()
model.fit(X_train, y_train)
print("const : {:.6f}".format(model.intercept_[0]))
print(pd.Series(model.coef_[0], model.feature_names_in_))
result :
const : 0.337668
sepal_length -0.001693
petal_length 0.231921
speceis_setosa -0.422260
speceis_versicolor 0.010399
speceis_virginica 0.411861
为什么statsmodels和sklearn的结果不一样?
此外,除了全部或部分one-hot-encoded特征外,两个模型的结果是相同的。
您包括了一整套单热编码虚拟变量作为回归量,这导致线性组合等于常数,因此您具有完美的多重共线性:您的协方差矩阵是奇异的,您不能将其逆.
在幕后 statsmodels
和 sklearn
都依赖于 Moore-Penrose 伪逆并且可以很好地反转奇异矩阵,问题是在奇异协方差矩阵情况下获得的系数不意味着任何物理意义上的任何东西。包之间的实现略有不同(sklearn
依赖于 scipy.stats.lstsq
,statsmodels
有一些自定义过程 statsmodels.tools.pinv_extended
,基本上是 numpy.linalg.svd
,变化很小),所以在一天结束时,它们都显示 «nonsense»(因为无法获得有意义的系数),这只是设计选择显示哪种 «nonsense»。
如果取one-hot encoded dummy的系数之和,可以看到statsmodels
等于常数,sklearn
等于0,而该常量不同于 statsmodels
常量。不对完全多重共线性“负责”的变量系数不受影响。