【问题标题】:Standardising / whitening / rescaling data by group with R使用 R 按组标准化/美白/重新缩放数据
【发布时间】:2015-12-01 03:40:39
【问题描述】:

我有一些分组数据,它们的特征范围非常不同。我想按组标准化每个功能。此外,我想在任意大的功能选择上执行此操作(按名称提供,例如下面的standardise.vars)。在 R 中执行此操作的最佳方法是什么?

到目前为止,我的方法在以下愚蠢的示例中给出:

DT <- data.table(mtcars)
group.vars <- c('cyl', 'am')
setkeyv(DT, group.vars)
standardise.vars <- c('disp','hp')
mns <- DT[, lapply(.SD, mean), .SDcols = standardise.cols, by = group.vars]
sds <- DT[, lapply(.SD, sd), .SDcols = standardise.cols, by = group.vars]
merged <- merge(mns, sds, suffixes = c('.mean', '.sd'))
DT[merged, ]

这给我留下了我的标准化列,旁边印有它们的平均值和标准差。我现在需要对所有列x 执行操作(x - x.mean) / x.std

     mpg cyl  disp  hp drat    wt  qsec vs am gear carb disp.mean   hp.mean   disp.sd    hp.sd
 1: 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4    2  135.8667  84.66667 13.969371 19.65536
 2: 22.8   4 140.8  95 3.92 3.150 22.90  1  0    4    2  135.8667  84.66667 13.969371 19.65536
 3: 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3    1  135.8667  84.66667 13.969371 19.65536
...

但是,我觉得这是一种不好的方法,我本可以一步实现标准化。非常感谢任何帮助、对我滥用 data.table 或可能使用 dplyr 的指示。

这种使用scale 的方法很接近,但它的格式不是很好(从scale 周围删除list(...) 会导致错误):

DT[, list(disp.scaled = list(scale(disp)), 
     hp.scaled = list(scale(hp))), by = .(cyl,am)]

   cyl am                                                        disp.scaled
1:   4  0                                    0.7755062, 0.3531536,-1.1286597
2:   4  1  0.7026252,-0.7282640,-0.8747715,-1.0994162,-0.7136133, 1.3033057,
3:   6  0                         1.1946100, 0.4570585,-0.8258343,-0.8258343
4:   6  1                                    0.5773503, 0.5773503,-1.1547005
5:   8  0  0.0331832, 0.0331832,-1.1391352,-1.1391352,-1.1391352, 1.5925615,
6:   8  1                                               0.7071068,-0.7071068
                                                            hp.scaled
1:                                   -1.1532051, 0.5257259, 0.6274793
2:  0.4910526,-0.7007155,-1.3186693,-0.7448550,-0.7007155, 0.4027735,
3:                        -0.5719714,-1.1167062, 0.8443388, 0.8443388
4:                                   -0.5773503,-0.5773503, 1.1547005
5: -0.5745432, 1.5237884,-0.4246623,-0.4246623,-0.4246623, 0.3247418,
6:                                              -0.7071068, 0.7071068

这种使用dplyr 的方法非常接近,但使用group_by_ 会做一些奇怪的事情(它适用于group_by):

ans <- DT %>% group_by(cyl, am) %>% 
    mutate_each_(funs(scale), standardise.vars)
ans2 <- DT %>% group_by_(group.vars) %>% 
    mutate_each_(funs(scale), standardise.vars)
truth <- filter(DT,am==0,cyl==4) %>% 
    transmute((disp - mean(disp))/sd(disp))
cbind(DT[,.(cyl,am,disp)], ans[,disp], ans2[,disp], truth)[1:3]

   cyl am  disp         V2       V3 (disp - mean(disp))/sd(disp)
1:   4  0 146.7  0.7755062 1.546750                    0.7755062
2:   4  0 140.8  0.3531536 1.327187                    0.3531536
3:   4  0 120.1 -1.1286597 0.556857                   -1.1286597

【问题讨论】:

  • 可以,但我可以按组将其应用于列表列吗?
  • 抱歉,如果我在这里有点密集,但我看不到在lapplyscale 中按组执行操作的选项。您介意在下面的答案中扩展您的解决方案吗?
  • 如果有帮助,我在上面添加了说明。

标签: r data.table dplyr


【解决方案1】:

假设我们想通过group.vars定义的组中的变量来标准化standardise.vars中的变量:

DT <- data.table(mtcars)
group.vars <- c('cyl', 'am')
standardise.vars <- c('disp','hp')

我认为dplyr 的这个解决方案可以解决它:

DT <- DT %>% group_by_(.dots=group.vars) %>% 
    mutate_each_(funs(scale), standardise.vars)

为了完整起见,您可以通过data.table 这样做:

myscale <- function(x){
    (x - mean(x)) / sd(x)
}
DT[, (standardise.vars) := lapply(.SD, myscale), 
   .SDcols = standardise.vars, by = group.vars]

【讨论】:

    猜你喜欢
    • 2015-01-13
    • 1970-01-01
    • 2015-12-11
    • 2018-04-03
    • 1970-01-01
    • 2021-05-30
    • 2019-01-21
    • 2018-04-13
    • 1970-01-01
    相关资源
    最近更新 更多