离散数据的归一化处理


这两种归一化公式解决的核心问题是一样的:让不同量级的特征"站在同一起跑线上",避免数值大的特征把数值小的特征的影响力淹没。


方式一:Min-Max 归一化

$$age_normalized = \frac{raw_age - age_min}{age_max - age_min}$$

直观理解:把原始值线性拉伸/压缩到 [0, 1] 这个固定区间内。

假设年龄范围是 18~80 岁:

原始年龄 计算过程 归一化结果
18 岁(最小) (18-18) / (80-18) = 0/62 0.0
49 岁(中间) (49-18) / (80-18) = 31/62 0.5
80 岁(最大) (80-18) / (80-18) = 62/62 1.0
  • 优点:结果范围固定在 [0, 1],直觉上最好理解。
  • 缺点:非常怕异常值。如果有个用户年龄填了 999 岁,age_max 就变成 999,导致正常用户的归一化值全部被压缩到 0 附近,失去区分度。

方式二:Z-score 标准化

$$asset_normalized = \frac{raw_asset - mean_asset}{std_asset}$$

直观理解:把原始值换算成"距离平均值有多少个标准差"的衡量单位。

假设资产均值是 50 万,标准差是 20 万:

原始资产 计算过程 标准化结果 含义
50 万(均值) (50-50) / 20 = 0 0.0 正好处于平均水平
70 万(均值+1σ) (70-50) / 20 = 1 +1.0 比平均高 1 个标准差
10 万(均值-2σ) (10-50) / 20 = -2 -2.0 比平均低 2 个标准差
  • 优点:对异常值更鲁棒,结果以 0 为中心,神经网络的 ReLU/BatchNorm 等层对这种分布的处理效果更好。
  • 缺点:结果没有固定的上下界(可能是 -3、+5 等),不如 Min-Max 直观。

两者如何选择(工业界经验)

场景 推荐方式
知道明确边界(如年龄 0~120) Min-Max
数据有异常值或分布不均匀(如资产、收入) Z-score
深度学习里的隐藏层激活 通常 Z-score 更稳定

一句话:Min-Max 是"把尺子缩放到 0~1",Z-score 是"把单位换算成标准差"。两者目的都是让不同特征的数值尺度一致,让模型更容易学习。

zscore的 mean计算

mean_asset 就是全体训练样本的资产算术平均值,计算方式非常直接:

$$mean_asset = \frac{1}{N} \sum_{i=1}^{N} raw_asset_i$$


在实际项目中怎么算

方式一:用 NumPy(离线/批量数据)

import numpy as np

raw_asset = np.array([10, 50, 100, 200, 500, ...])  # 所有用户的原始资产

mean_asset = raw_asset.mean()    # 均值
std_asset  = raw_asset.std()     # 标准差

# 归一化
asset_normalized = (raw_asset - mean_asset) / std_asset

方式二:用 scikit-learn(工业界推荐)

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(train_asset)              # 只用训练集来算 mean 和 std
asset_normalized = scaler.transform(raw_asset)  # 用训练集的统计量来转换

工业界的一个重要细节:只能用训练集算

这是面试常考的点:

                     ✅ 正确做法                ❌ 错误做法
计算 mean/std 用    只用「训练集」数据          用「全量数据」(含测试集)

为什么不能用全量数据(含测试集)来算 mean?

因为测试集模拟的是"未来的用户",在真实上线场景里你是看不到未来数据的。如果用了测试集数据来算 mean,相当于模型提前"偷看了答案",这在机器学习里叫做数据泄露(Data Leakage),会导致离线评估虚高,线上效果一落千丈。


线上服务时怎么用

训练完成后,mean_assetstd_asset 这两个统计量需要持久化保存下来(比如存成 JSON 或 pkl 文件),线上推理时直接加载使用:

# 离线训练时保存
stats = {"mean": float(mean_asset), "std": float(std_asset)}
json.dump(stats, open("asset_stats.json", "w"))

# 线上推理时加载
stats = json.load(open("asset_stats.json"))
asset_normalized = (user_raw_asset - stats["mean"]) / stats["std"]

一句话mean_asset 就是把训练集里所有用户的资产加起来除以人数,然后把这个值存下来,线上遇到新用户时直接拿来用。

posted @ 2026-03-26 08:53  向着朝阳  阅读(5)  评论(0)    收藏  举报