有时,输入特征与目标变量之间的关系并非简单的线性关系。此外,一个特征的影响可能随另一个特征的值而变化。线性模型在其基本形式下难以捕捉这些复杂性。创建交互项和多项式特征,即使是线性模型,也能表示数据中更复杂的模式。多项式特征:捕捉非线性关系设想您有一个特征 $x$,并且与您的目标 $y$ 的关系更像一条曲线而非直线。一个简单的线性模型假设 $y \approx w_1x + w_0$,这无法很好地拟合曲线。多项式特征通过添加现有特征的幂次方作为新特征来解决此问题。例如,如果您有一个单特征 $x_1$,生成2次多项式特征将您的特征集从 $[x_1]$ 转换为 $[1, x_1, x_1^2]$。这里的 '1' 表示截距或偏置项。如果您有两个特征 $x_1$ 和 $x_2$,进行2次多项式变换将生成 $[1, x_1, x_2, x_1^2, x_1x_2, x_2^2]$。请注意,这包括原始特征、它们的平方项,以及表示它们之间交互的项 ($x_1x_2$)。通过添加像 $x_1^2$ 这样的项,您使得线性模型能够拟合二次关系: $$ y \approx w_1x_1 + w_2x_1^2 + w_0 $$ 这个等式对于 系数 ($w_1, w_2, w_0$) 来说仍然是线性的,这是线性模型算法关注的重点。您实际上已经转换了特征空间,因此线性模型可以在原始空间中找到非线性的决策边界或回归曲线。Scikit-learn 为此提供了 PolynomialFeatures 转换器。让我们看一个简单例子:import numpy as np import pandas as pd from sklearn.preprocessing import PolynomialFeatures # 包含一个特征的样本数据 X = np.arange(6).reshape(6, 1) print("原始特征 (X):") print(X) # 创建2次多项式特征 poly = PolynomialFeatures(degree=2, include_bias=False) # 排除偏置列 X_poly = poly.fit_transform(X) print("\n多项式特征 (2次):") print(X_poly) print("\n特征名称:") print(poly.get_feature_names_out(['x1']))Output:Original Features (X): [[0] [1] [2] [3] [4] [5]] Polynomial Features (degree 2): [[ 0. 0.] [ 1. 1.] [ 2. 4.] [ 3. 9.] [ 4. 16.] [ 5. 25.]] Feature names: ['x1' 'x1^2']如您所见,该转换器添加了一个新特征,表示原始特征 $x_1$ 的平方。让我们看看这如何帮助拟合非线性数据。考虑由二次函数 $y = 0.5x^2 - x + 2 + noise$ 生成的数据。标准线性回归表现会不佳。如果我们首先对 $x$ 应用2次多项式变换,线性回归就能更好地拟合曲线。{"layout": {"title": "线性回归与多项式回归拟合", "xaxis": {"title": "特征 (x)"}, "yaxis": {"title": "目标 (y)"}, "legend": {"title": {"text": "模型"}}}, "data": [{"x": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "y": [1.8, 1.7, 2.1, 3.5, 5.2, 7.8, 10.1, 14.2, 17.5, 21.8, 27.1], "mode": "markers", "name": "数据点", "marker": {"color": "#339af0"}}, {"x": [0, 10], "y": [2.5, 22.5], "mode": "lines", "name": "线性拟合", "line": {"color": "#fa5252", "dash": "dash"}}, {"x": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], "y": [2.0, 1.5, 2.0, 3.5, 6.0, 9.5, 14.0, 19.5, 26.0, 33.5, 42.0], "mode": "lines", "name": "多项式(2次)拟合", "line": {"color": "#40c057"}}]}标准线性模型(红色虚线)未能捕捉数据点(蓝色点)中的曲线,而应用于2次多项式特征的线性模型(实心绿线)提供了更好的拟合。尽管功能强大,添加多项式特征会大幅增加数据集的维度。对于 $n$ 个特征的 $d$ 次多项式,可以生成大约 $n^d$ 个新特征。这增加了计算成本,并提高了过拟合的风险,即模型学习了训练数据中的噪声而非潜在模式。正则化技术或后续的特征选择变得更加重要。交互项:捕捉依赖关系有时一个特征的影响取决于另一个特征的水平。例如,在预测房价时,额外的卧室(num_bedrooms)所增加的价值对于大面积(sqft)的房屋可能远高于小面积的房屋。一个简单的加性模型无法捕捉到这一点;它会假设每间卧室的价格增长是恒定的,无论房屋大小。交互项是通过将两个或多个原始特征相乘创建的特征。在房价示例中,添加特征 num_bedrooms * sqft 使得模型能够学习这种组合效应。我们之前看到的 PolynomialFeatures 转换器默认会生成交互项。当我们为 $[x_1, x_2]$ 生成2次特征时,我们得到了 $[1, x_1, x_2, x_1^2, x_1x_2, x_2^2]$。其中 $x_1x_2$ 项就是交互项。如果您 只 想要交互项而不需要多项式项(如 $x_1^2$),可以设置 interaction_only=True。# 包含两个特征的样本数据 X_two = np.arange(8).reshape(4, 2) print("原始特征:") print(pd.DataFrame(X_two, columns=['x1', 'x2'])) # 仅包含交互项(相当于 degree=2, interaction_only=True) poly_interact = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False) X_interact = poly_interact.fit_transform(X_two) print("\n仅包含交互项的特征:") print(pd.DataFrame(X_interact, columns=poly_interact.get_feature_names_out(['x1', 'x2']))) # 包含多项式和交互项(degree=2, interaction_only=False) poly_full = PolynomialFeatures(degree=2, include_bias=False) X_full_poly = poly_full.fit_transform(X_two) print("\n包含多项式(2次)和交互项的特征:") print(pd.DataFrame(X_full_poly, columns=poly_full.get_feature_names_out(['x1', 'x2']))) Output:Original Features: x1 x2 0 0 1 1 2 3 2 4 5 3 6 7 Features with Interactions Only: x1 x2 x1 x2 0 0 1 0.0 1 2 3 6.0 2 4 5 20.0 3 6 7 42.0 Features with Polynomial (degree 2) and Interactions: x1 x2 x1^2 x1 x2 x2^2 0 0 1 0.0 0.0 1.0 1 2 3 4.0 6.0 9.0 2 4 5 16.0 20.0 25.0 3 6 7 36.0 42.0 49.0交互项使得模型能够学习特征如何相互影响,从而在存在此类关系时可能获得更准确的预测。实际考量特征缩放: 多项式特征(例如 $x^2, x^3$)与原始特征或交互项相比,其尺度可能明显不同。通常建议在生成多项式和交互特征 之后 应用特征缩放(例如使用 StandardScaler 进行标准化),特别是对于对特征量级敏感的模型(例如正则化线性模型、支持向量机、神经网络)。复杂度管理: 如前所述,这些技术可以大幅增加特征数量。最初可以从低阶(例如2次)开始,并且只考虑特征对之间的交互。利用领域知识来假设哪些交互可能具有意义。后续讨论的技术,例如正则化(L1可以执行特征选择)和显式特征选择方法,对于管理这些生成特征引入的复杂度非常重要。基于树的模型,如随机森林或梯度提升,本身就能够捕捉某些特征交互,尽管显式交互项有时仍然可以提高它们的性能。通过深思熟虑地创建多项式和交互特征,您为机器学习模型提供了理解数据中更复杂关系所需的构建块,这通常会提升预测性能。然而,这种能力也伴随着管理由此产生的模型复杂度的责任。