R语言使用指定上下界矩阵将data.table数值列缩放至单位区间
data.table按指定上下界缩放数值列问题
问题场景
存在同时包含数值型与因子型数据的data.table对象,示例数据如下:
> dat x z y w 1: 3.307590 -1.66951137 b a 2: 1.809447 4.10331322 b b 3: 3.314621 3.69436879 a a 4: 1.896529 -0.08143017 c b 5: 3.317341 1.01839533 c a 6: 1.806456 -2.09547272 a b ...
需要将其中的数值变量x、z缩放到单位区间。各数值列的最小值和最大值存储在独立矩阵中(注意最大值并非直接取对应列的max值),矩阵第一行为各数值列的最小值,第二行为最大值,矩阵示例如下:
> cts.mat x z [1,] 1 -3 [2,] 4 5
原有尝试的问题
曾尝试通过如下代码实现缩放:
dat[, lapply(.SD, range01, cts.mat), .SDcol = c("x", "z")]
配套自定义的range01函数如下:
range01 <- function(x, cts.mat) { x.as.string <- deparse(substitute(x)) # 缩放公式:(x-下界)/(上界-下界) (x - cts.mat[, x.as.string][1]) / (cts.mat[, x.as.string][2] - cts.mat[, x.as.string][1]) }
上述代码无法正常运行,核心问题是lapply遍历.SD列时,传入函数的是纯取值向量,无法通过substitute捕获到原始列名,因此不能匹配到矩阵中对应列的上下界参数。
可行解决方案
方案1:直接遍历列名做计算(最高效,推荐)
不需要在lapply中依赖列名捕获,直接遍历要缩放的列名字符串,匹配矩阵中对应的上下界完成计算,支持原地更新数据,非数值列不会受影响:
# 指定要缩放的数值列 scale_cols <- c("x", "z") # 按列匹配上下界完成缩放,原地替换原列 dat[, (scale_cols) := lapply(scale_cols, function(col_name) { lower <- cts.mat[1, col_name] upper <- cts.mat[2, col_name] (get(col_name) - lower) / (upper - lower) })]
方案2:封装可复用缩放函数
如果需要单独封装缩放逻辑,可以显式传入上下界参数,避免依赖环境捕获:
# 纯计算逻辑的缩放函数,不需要内部取列名 range01 <- function(x, lower, upper) { (x - lower) / (upper - lower) } # 用mapply按列匹配传入对应的列值、下界、上界 dat[, (scale_cols) := mapply(function(col_name, l, u) { range01(get(col_name), l, u) }, scale_cols, cts.mat[1, scale_cols], cts.mat[2, scale_cols])]
两种方案的计算逻辑完全一致:以给定的cts.mat为例,x列按(x-1)/(4-1)计算,z列按(z+3)/(5+3)计算,即使原始数据存在超出列本身min/max的值,也会严格按照矩阵中给定的上下界完成缩放。
内容的提问来源于stack exchange,提问作者user31313
相关产品推荐
相关产品推荐

