我尝试用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学习
# 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的结果不同?
此外,除了一个热编码特征的全部或部分之外,这两个模型的结果是相同的。
您包含了一组完整的热编码假人作为回归器,这会产生一个等于常数的线性组合,因此您具有完美的多重共线性:您的协方差矩阵是奇异的,不能取其逆。
在statsmodels
和sklearn
都依赖Moore-Penrose伪逆并且可以很好地逆奇异矩阵的情况下,问题是在奇异协方差矩阵情况下获得的系数在任何物理意义上都没有任何意义。包之间的实现有点不同(sklearn
依赖于scipy.stats.lstsq
,statsmodels
有一些自定义过程statsmodels.tools.pinv_extended
,基本上是变化最小的numpy.linalg.svd
(,所以在一天结束时,它们都显示"无意义"(因为无法获得有意义的系数(,这只是显示哪种"无意义的"的设计选择。
如果你取一个热编码假人的系数之和,你可以看到,对于statsmodels
,它等于常数,而对于sklearn
,它等于0,而常数不同于statsmodels
常数。不"负责"完美多重共线性的变量的系数不受影响。