标准化测试数据集时如何不使用scale函数提升计算精度
问题本质
你遇到的量级10^-2的误差并非计算精度导致,而是自定义标准化代码存在广播逻辑错误:R的矩阵向量化运算默认按列优先顺序循环匹配向量元素,直接写a - colMeans(a)并不会实现「每列减去对应列均值」的效果,而是将长度为列数的均值向量,按顺序循环匹配矩阵的所有元素,完全不符合中心化的逻辑要求。
正确的自定义标准化实现
你可以用以下两种写法实现和内置scale函数完全一致的精度,同时可自行存储训练集的均值、标准差参数用于测试集处理:
set.seed(5) a = matrix(rnorm(30000, mean=10, sd=5), 10000, 3) # 提前计算训练集的均值和标准差,可单独存储用于后续测试集标准化 train_mean = colMeans(a) train_sd = apply(a, 2, sd) # 正确写法1:用sweep函数指定按列操作 a_scale_custom1 = sweep(a, 2, train_mean, FUN = "-") a_scale_custom1 = sweep(a_scale_custom1, 2, train_sd, FUN = "/") # 正确写法2:转置矩阵后运算再转回,利用转置后维度匹配逻辑 a_scale_custom2 = t((t(a) - train_mean) / train_sd) # 验证和scale函数结果一致 all.equal(a_scale_custom1, scale(a), check.attributes = FALSE) # 输出为 TRUE colMeans(a_scale_custom1) # 输出和scale结果一致,为1e-16量级的正常浮点误差
训练/测试集标准化复用参数的实践
如果你需要用训练集的统计量标准化测试集,除了上述自定义写法,也可以直接提取scale函数返回结果的属性值复用,逻辑更简洁:
# 训练集标准化 train_scaled = scale(train_data) # 提取训练集的均值、标准差,单独存储 train_center = attr(train_scaled, "scaled:center") train_scale_param = attr(train_scaled, "scaled:scale") # 测试集用训练集参数直接标准化 test_scaled = scale(test_data, center = train_center, scale = train_scale_param)
内容的提问来源于stack exchange,提问作者Álvaro Méndez Civieta
相关产品推荐
相关产品推荐

