Hastie、Tibshirani 和 Friedman(以下称为HTF )一书中的常设示例之一使用来自Stamey等人的一项研究的前列腺癌数据(可在此处获得并在此处描述)。(1989 年)。
我试图重现 HTF(第二版)中引用的普通线性回归的结果,它们报告了以下系数(表 3.2,第 50 页):
Intercept: 2.45
lcavol : 0.72
weight : 0.29
age : -0.14
lbph : 0.21
svi : 0.31
lip : -0.29
gleason : -0.02
egg45 : 0.28
然而,我自己的分析给出了可悲的不同数字(使用scikit-learn's LinearRegression,statsmodels'sOLS并使用 HTF 中的公式 3.6 手动计算系数)。我明白了
Intercept: 0.429
lcavol : 0.577
lweight : 0.614
age : -0.019
lbph : 0.145
svi : 0.737
lcp : -0.206
gleason : -0.030
pgg45 : 0.009
使用以下(Python 3)代码:
# Import data
# -----------
import pandas as pd
df = pd.read_csv('prostate.data', sep='\t', usecols=range(1, 11))
# Extract training set used by HTF
# --------------------------------
train_mask = (df['train'] == 'T')
cols_X = [col for col in df.columns if col not in ['lpsa', 'train']]
cols_y = ['lpsa']
X_train = df.loc[train_mask, cols_X]
y_train = df.loc[train_mask, cols_y]
# Use scikit-learn's LinearRegression
# -----------------------------------
from sklearn import linear_model
ols = linear_model.LinearRegression(normalize=True)
ols.fit(X_train, y_train)
print('Intercept: {:6.3f}'.format(ols.intercept_[0]))
for i, col in enumerate(X_train.columns):
print('{:9s}: {:6.3f}'.format(col, ols.coef_[0, i]))
# Use statsmodels OLS
# -------------------
import statsmodels.api as sm
result = sm.OLS(y_train, sm.add_constant(X_train)).fit()
print(result.summary())
# Use formula 3.6 of HTF
# ----------------------
X_ext = np.hstack([np.ones((X_train.shape[0], 1)), X_train.values])
np.matmul(np.matmul(np.linalg.inv(np.matmul(X_ext.T, X_ext)), X_ext.T), y_train)
我做错了什么,还是书中报告的数字有误?
编辑:重新定义
X_train = (X_train - X_train.mean(axis=0)) / (X_train.std(axis=0))
在任何拟合导致系数与 HTF 中报告的系数一致之前:
Intercept: 2.4523
lcavol: 0.7164
weight: 0.2926
age: -0.1425
lbph: 0.2120
svi: 0.3096
lip: -0.2890
gleason: -0.0209
pgg45: 0.2773
这本书可能会受益于使这一点更清晰(我见过其他人对同样的问题感到困惑)。感谢所有回复!