<p>直接用 (x - x.min()) / (x.max() - x.min()) 会因全等值导致除零错误,需用 np.where 判断极差为零并设为常量;二维归一化须用 keepdims=True 对齐维度,并用 np.nanmin/np.nanmax 处理 NaN,且应缓存极值避免重复计算。</p>

为什么直接用 (x - x.min()) / (x.max() - x.min()) 会出错?
因为当数组所有值相等时,x.max() - x.min() 为 0,除零导致 nan 或 inf。这不是边缘情况——真实数据中常有全零特征、单值列或缺失值填充后的恒定列。
正确做法是显式处理分母为零的情形:
- 用
np.where切换:当极差为 0,直接返回全 0(或全 0.5,取决于归一化目标区间) - 避免用
np.divide的where=参数替代,它不改变被除数为 0 时的广播行为 - 别依赖
sklearn.preprocessing.MinMaxScaler的默认容错——它内部确实做了防零处理,但手动实现时必须自己加
如何对二维数组按列归一化并保留原始 shape?
常见错误是写成 (x - x.min(axis=0)) / (x.max(axis=0) - x.min(axis=0)) 却没处理 axis=0 下的维度对齐问题。NumPy 广播要求减法/除法时维度可匹配,而 x.min(axis=0) 返回的是 1D 向量,不能直接和二维 x 运算。
必须用 keepdims=True 保持维度:
立即学习“Python免费学习笔记(深入)”;
min_vals = x.min(axis=0, keepdims=True)<br>max_vals = x.max(axis=0, keepdims=True)<br>range_vals = max_vals - min_vals<br>x_norm = np.where(range_vals == 0, 0, (x - min_vals) / range_vals)
注意:keepdims=True 让 min_vals 形状变成 (1, n_features),才能正确广播到 (n_samples, n_features) 的 x 上。
归一化后数值不在 [0, 1] 区间?检查输入是否含 nan
np.min() 和 np.max() 遇到 nan 默认返回 nan,导致整个结果崩坏。不是所有数据清洗都提前去 nan,尤其读取 CSV 时 pd.read_csv 默认把空字符串转成 nan,但 NumPy 不自动跳过。
安全写法:
- 用
np.nanmin()和np.nanmax()替代min()/max() - 但要注意:若整列全是
nan,np.nanmin仍返回nan,需额外判断np.all(np.isnan(x), axis=0) - 更稳妥的是先用
np.isfinite(x)掩码过滤,再计算极值
性能关键:避免重复计算 min 和 max
在循环中反复调用 x.min() 和 x.max() 看似简洁,实则触发两次完整遍历。对百万级数组,这会让耗时翻倍。
应一次性算出并复用:
mins = np.nanmin(x, axis=0, keepdims=True)<br>maxs = np.nanmax(x, axis=0, keepdims=True)<br>ranges = maxs - mins<br># 后续直接用 mins/maxs/ranges,不再调用 min/max
如果后续还要反向还原(denormalize),也建议把 mins 和 ranges 缓存下来——它们比存原始数据轻得多,且避免重复扫描。
实际项目里,最易被忽略的是全常量列的零除保护和 nan 值的传播路径;这两点不处理,模型训练可能无声失败。


















