虽然标准化将数据中心置于零点并根据标准差进行缩放,但归一化(通常称为最小-最大值缩放)采用不同的方法。它的主要目的是将数值特征重新缩放到一个特定、预设的范围内,最常见的是 [0, 1]。当您需要将特征限制在一个一致的区间内时,这种技术尤其有用。这对于不强烈依赖数据分布假设的算法(与标准化不同,标准化适用于近似高斯分布),或者对于计算距离或使用梯度下降的算法通常有益,因为特征尺度差异大可能会导致问题。图像处理常使用归一化来缩放像素强度,像素强度自然落在 [0, 255] 等范围内,并将其缩放到 [0, 1]。最小-最大值缩放公式这种转换通过以下公式对每个特征 $X$ 实现:$$ X_{\text{归一化}} = \frac{X - X_{\min}}{X_{\max} - X_{\min}} $$这里:$X$ 是原始特征值。$X_{\min}$ 是该特征在训练数据中观测到的最小值。$X_{\max}$ 是该特征在训练数据中观测到的最大值。这个公式将原始特征范围 $[X_{\min}, X_{\max}]$ 线性映射到新范围 [0, 1]。如果一个值等于最小值 ($X_{\min}$),它将被映射到 0。如果它等于最大值 ($X_{\max}$),它将被映射到 1。所有其他值按比例落在两者之间。虽然 [0, 1] 是最常见的目标范围,但该公式可以推广以缩放到任意范围 $[a, b]$:$$ X_{\text{归一化}} = a + \frac{(X - X_{\min})(b - a)}{X_{\max} - X_{\min}} $$然而,Scikit-learn 的实现默认使用 [0, 1] 范围,这足以应对大多数使用场景。Scikit-learn 实现Scikit-learn 通过 sklearn.preprocessing 模块中的 MinMaxScaler 类提供便捷实现。像 Scikit-learn 中的其他转换器一样,它遵循 fit 和 transform 模式。重要提示: 缩放器必须仅使用训练数据进行拟合。在此 fit 步骤中获得的最小值 ($X_{\min}$) 和最大值 ($X_{\max}$) 随后用于 transform 训练数据和任何后续数据(如验证集或测试集)。这避免了测试集信息渗入预处理步骤,从而确保对模型性能的准确评估。以下是一个基本例子:import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler from sklearn.model_selection import train_test_split # 示例数据 data = {'Feature1': np.random.rand(100) * 100, 'Feature2': np.random.rand(100) * 50 - 25} # 包含负值 df = pd.DataFrame(data) # 添加一个异常值以说明敏感性 df.loc[100] = {'Feature1': 1000, 'Feature2': 200} # 分割数据(在拟合缩放器之前必不可少) X_train, X_test = train_test_split(df, test_size=0.2, random_state=42) # 初始化缩放器 scaler = MinMaxScaler(feature_range=(0, 1)) # 默认范围 # 仅在训练数据上拟合缩放器 scaler.fit(X_train) # 转换训练和测试数据 X_train_scaled = scaler.transform(X_train) X_test_scaled = scaler.transform(X_test) # 结果是 NumPy 数组。如果需要,可转换回 DataFrame。 X_train_scaled_df = pd.DataFrame(X_train_scaled, columns=X_train.columns, index=X_train.index) X_test_scaled_df = pd.DataFrame(X_test_scaled, columns=X_test.columns, index=X_test.index) print("原始训练数据示例:\n", X_train.head()) # print("\n学习到的最小值:", scaler.data_min_) # 从训练数据学习到的最小值 # print("学习到的最大值:", scaler.data_max_) # 从训练数据学习到的最大值 print("\n缩放后的训练数据示例:\n", X_train_scaled_df.head()) print("\n缩放后的测试数据示例:\n", X_test_scaled_df.head()) # 验证缩放后训练数据的范围(应接近 0 和 1) print("\n缩放后训练数据最小值:\n", X_train_scaled_df.min()) print("\n缩放后训练数据最大值:\n", X_train_scaled_df.max()) # 注意:如果测试数据包含训练期间观测范围之外的值, # 缩放后的值可能会超出 [0, 1] 范围。这是预期行为。 print("\n缩放后测试数据最小值:\n", X_test_scaled_df.min()) print("\n缩放后测试数据最大值:\n", X_test_scaled_df.max())注意 scaler.fit() 只调用一次,使用 X_train。 X_train 和 X_test 随后都使用 scaler.transform() 进行缩放。效果可视化最小-最大值缩放将数据压缩到 [0, 1] 范围,但保留了分布的整体形状。然而,异常值会很大程度影响其他数据点的缩放。{"layout": {"title": "最小-最大值缩放的效果 (Feature1)", "xaxis": {"title": "原始值"}, "xaxis2": {"title": "缩放后的值 [0, 1]", "overlaying": "x", "side": "top"}, "yaxis": {"title": "密度"}, "barmode": "overlay", "legend": {"traceorder": "reversed"}}, "data": [{"type": "histogram", "x": [10.748848, 66.440045, 90.898395, 93.638964, 83.357346, 46.401541, 66.896927, 44.892747, 24.768448, 50.040081, 85.992009, 98.323344, 23.136783, 69.111684, 68.737355, 65.087031, 85.203563, 91.194662, 62.917724, 23.166828, 66.592676, 16.476868, 59.705388, 80.86752 , 73.014096, 39.639268, 84.276763, 99.817201, 12.105387, 2.117063, 21.821975, 39.716468, 66.37114 , 13.670098, 32.991969, 76.275787, 25.710626, 39.807265, 15.12043 , 77.879097, 56.222032, 48.874918, 92.191937, 59.544585, 89.17144 , 16.171238, 21.172474, 79.520367, 79.011445, 71.487032, 58.136605, 81.829745, 53.411769, 61.871056, 80.935861, 2.050546, 82.250563, 38.882915, 45.644678, 7.323993, 70.978237, 44.519281, 33.83042 , 76.136188, 54.33663 , 91.964635, 56.768933, 5.174568, 48.666415, 8.385878, 71.767646, 5.326651, 30.44163 , 3.958079, 45.008896, 6.805295, 26.934695, 73.767648, 97.158385, 1000.0], "name": "原始数据", "histnorm": "probability density", "marker": {"color": "#74c0fc", "line": {"color": "#1c7ed6", "width": 1}}, "opacity": 0.75}, {"type": "histogram", "x": [0.008617, 0.064433, 0.089049, 0.091803, 0.081464, 0.044305, 0.064892, 0.042786, 0.022574, 0.047965, 0.084114, 0.096515, 0.020932, 0.067119, 0.066743, 0.063071, 0.08332 , 0.089347, 0.060891, 0.020962, 0.064586, 0.014237, 0.05766 , 0.078958, 0.071045, 0.037494, 0.082387, 0.098018, 0.009974, 0.0000 , 0.019608, 0.037572, 0.064364, 0.011544, 0.030797, 0.074326, 0.023522, 0.037663, 0.012989, 0.075939, 0.054148, 0.04679 , 0.09035 , 0.0575 , 0.087311, 0.013929, 0.018953, 0.07759 , 0.077079, 0.069506, 0.056081, 0.079927, 0.051321, 0.059838, 0.079026, 0.0000 , 0.080351, 0.036732, 0.043543, 0.005178, 0.06899 , 0.04241 , 0.031641, 0.074185, 0.052251, 0.090121, 0.054698, 0.003018, 0.04658 , 0.006244, 0.069788, 0.003171, 0.028228, 0.001798, 0.042903, 0.004655, 0.024753, 0.071799, 0.095344, 1.0], "name": "最小-最大值缩放后", "xaxis": "x2", "histnorm": "probability density", "marker": {"color": "#ffc078", "line": {"color": "#f76707", "width": 1}}, "opacity": 0.75}]}分布形状得以保留,但范围被压缩到 [0, 1]。请注意,单个大的异常值 (1000) 的存在如何将大部分数据点在缩放后的版本中挤压到 [0, 1] 范围的很小一部分。优点与缺点优点:固定范围: 确保所有特征都具有完全相同的尺度,通常是 [0, 1]。这有助于可视化,并对特征幅度敏感的算法有帮助。保留关系: 保持特征值之间的关系。它不改变分布本身的形状。算法兼容性: 适用于需要有界输入范围的算法,例如神经网络中的某些激活函数(如 Sigmoid 或 Tanh,尽管 ReLU 激活通常与标准化配合更好)。缺点:对异常值的敏感性: 这是最主要的缺点。由于缩放直接取决于最小值和最大值,异常值会大大缩小“正常”数据点的范围,将它们压缩到一个非常小的区间。这会降低该特征对许多算法的有用性。不中心化数据: 与标准化不同,最小-最大值缩放不将数据中心置于零均值。某些算法在使用零中心化数据时表现更好。新数据问题: 如果测试集中出现的新数据点超出训练期间观测到的原始 $[X_{\min}, X_{\max}]$ 范围,缩放后的值将超出目标 [0, 1] 范围。虽然不一定是错误(它反映新数据超出了训练分布的观测边界),但这是一个需要注意的事项。何时使用最小-最大值缩放在以下情况下选择最小-最大值缩放:您知道数据很少或没有明显的异常值,或者您已经处理了它们。您需要将特征严格限制在特定范围内,例如 [0, 1] 或 [-1, 1]。您使用的算法不假设特定数据分布(如高斯分布)。例子包括 K-近邻 (KNN) 或图像处理中使用的算法。您优先考虑所有特征具有完全相同的数值尺度,而不是中心化数据或可靠地处理异常值。如果您的数据包含明显的异常值,或者您的算法得益于零均值和单位方差的数据(如 PCA、SVM、逻辑回归、线性回归),那么标准化或缩放(将在下文讨论)通常是更好的选择。总之,最小-最大值缩放是将特征带到共同尺度的一种直接方法,但它对异常值的敏感性需要仔细考虑。始终记住在训练数据上拟合缩放器,并一致地转换训练集和测试集。