在回归模型中转换目标的效果

在此示例中,我们概述了sklearn.compose.TransformedTargetRegressor。 两个示例说明了在学习线性回归模型之前转换目标的好处。 第一个示例使用合成数据,而第二个示例基于Boston住房数据集。

# 作者: Guillaume Lemaitre <guillaume.lemaitre@inria.fr>
# 执照: BSD 3 clause


import numpy as np
import matplotlib
import matplotlib.pyplot as plt
from distutils.version import LooseVersion

print(__doc__)

综合实例

from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.linear_model import RidgeCV
from sklearn.compose import TransformedTargetRegressor
from sklearn.metrics import median_absolute_error, r2_score


# `normed` is being deprecated in favor of `density` in histograms
if LooseVersion(matplotlib.__version__) >= '2.1':
    density_param = {'density'True}
else:
    density_param = {'normed'True}

生成了一个综合随机回归问题。 通过以下方式修改目标y:(i)转换所有目标,使所有条目均为非负数;(ii)应用指数函数以获得无法使用简单线性模型拟合的非线性目标。

因此,在训练线性回归模型并将其用于预测之前,将使用对数(np.log1p)和指数函数(np.expm1)转换目标。

X, y = make_regression(n_samples=10000, noise=100, random_state=0)
y = np.exp((y + abs(y.min())) / 200)
y_trans = np.log1p(y)

下面说明在应用对数函数之前和之后目标的概率密度函数。

f, (ax0, ax1) = plt.subplots(12)

ax0.hist(y, bins=100, **density_param)
ax0.set_xlim([02000])
ax0.set_ylabel('Probability')
ax0.set_xlabel('Target')
ax0.set_title('Target distribution')

ax1.hist(y_trans, bins=100, **density_param)
ax1.set_ylabel('Probability')
ax1.set_xlabel('Target')
ax1.set_title('Transformed target distribution')

f.suptitle("Synthetic data", y=0.035)
f.tight_layout(rect=[0.050.050.950.95])

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

首先,将线性模型应用于原始目标。 由于非线性,训练的模型在预测期间将不精确。 随后,使用对数函数将目标线性化,即使使用中位数绝对误差(MAE)报告的相似线性模型,也可以实现更好的预测。

f, (ax0, ax1) = plt.subplots(12, sharey=True)

regr = RidgeCV()
regr.fit(X_train, y_train)
y_pred = regr.predict(X_test)

ax0.scatter(y_test, y_pred)
ax0.plot([02000], [02000], '--k')
ax0.set_ylabel('Target predicted')
ax0.set_xlabel('True Target')
ax0.set_title('Ridge regression \n without target transformation')
ax0.text(1001750r'$R^2$=%.2f, MAE=%.2f' % (
    r2_score(y_test, y_pred), median_absolute_error(y_test, y_pred)))
ax0.set_xlim([02000])
ax0.set_ylim([02000])

regr_trans = TransformedTargetRegressor(regressor=RidgeCV(),
                                        func=np.log1p,
                                        inverse_func=np.expm1)
regr_trans.fit(X_train, y_train)
y_pred = regr_trans.predict(X_test)

ax1.scatter(y_test, y_pred)
ax1.plot([02000], [02000], '--k')
ax1.set_ylabel('Target predicted')
ax1.set_xlabel('True Target')
ax1.set_title('Ridge regression \n with target transformation')
ax1.text(1001750r'$R^2$=%.2f, MAE=%.2f' % (
    r2_score(y_test, y_pred), median_absolute_error(y_test, y_pred)))
ax1.set_xlim([02000])
ax1.set_ylim([02000])

f.suptitle("Synthetic data", y=0.035)
f.tight_layout(rect=[0.050.050.950.95])

实际数据集

以类似的方式,波士顿住房数据集用于显示学习模型之前变换目标的影响。 在此示例中,要预测的目标对应于到五个波士顿就业中心的加权距离。

from sklearn.datasets import load_boston
from sklearn.preprocessing import QuantileTransformer, quantile_transform

dataset = load_boston()
target = np.array(dataset.feature_names) == "DIS"
X = dataset.data[:, np.logical_not(target)]
y = dataset.data[:, target].squeeze()
y_trans = quantile_transform(dataset.data[:, target],
                             n_quantiles=300,
                             output_distribution='normal',
                             copy=True).squeeze()

使用sklearn.preprocessing.QuantileTransformer,以便在应用sklearn.linear_model.RidgeCV模型之前,目标遵循正态分布。

f, (ax0, ax1) = plt.subplots(12)

ax0.hist(y, bins=100, **density_param)
ax0.set_ylabel('Probability')
ax0.set_xlabel('Target')
ax0.set_title('Target distribution')

ax1.hist(y_trans, bins=100, **density_param)
ax1.set_ylabel('Probability')
ax1.set_xlabel('Target')
ax1.set_title('Transformed target distribution')

f.suptitle("Boston housing data: distance to employment centers", y=0.035)
f.tight_layout(rect=[0.050.050.950.95])

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)

转换器的影响要弱于综合数据。 但是,该变换引起MAE的降低。

f, (ax0, ax1) = plt.subplots(12, sharey=True)

regr = RidgeCV()
regr.fit(X_train, y_train)
y_pred = regr.predict(X_test)

ax0.scatter(y_test, y_pred)
ax0.plot([010], [010], '--k')
ax0.set_ylabel('Target predicted')
ax0.set_xlabel('True Target')
ax0.set_title('Ridge regression \n without target transformation')
ax0.text(19r'$R^2$=%.2f, MAE=%.2f' % (
    r2_score(y_test, y_pred), median_absolute_error(y_test, y_pred)))
ax0.set_xlim([010])
ax0.set_ylim([010])

regr_trans = TransformedTargetRegressor(
    regressor=RidgeCV(),
    transformer=QuantileTransformer(n_quantiles=300,
                                    output_distribution='normal'))
regr_trans.fit(X_train, y_train)
y_pred = regr_trans.predict(X_test)

ax1.scatter(y_test, y_pred)
ax1.plot([010], [010], '--k')
ax1.set_ylabel('Target predicted')
ax1.set_xlabel('True Target')
ax1.set_title('Ridge regression \n with target transformation')
ax1.text(19r'$R^2$=%.2f, MAE=%.2f' % (
    r2_score(y_test, y_pred), median_absolute_error(y_test, y_pred)))
ax1.set_xlim([010])
ax1.set_ylim([010])

f.suptitle("Boston housing data: distance to employment centers", y=0.035)
f.tight_layout(rect=[0.050.050.950.95])

plt.show()

脚本的总运行时间:(0分钟1.447秒)