【问题标题】:scale in data.table in r在 r 中的 data.table 中缩放
【发布时间】:2019-10-24 11:13:47
【问题描述】:
       LC  RC TOEIC eua again  class
   1: 490 390   880  90     0 100818
   2: 495 395   890  90     0 100818
   3: 490 330   820  90     0 100818
   4: 495 460   955  96     0 100818
   5: 495 370   865  91     0 100818
  ---                               
1021: 470 400   870  61     0 100770
1022: 260 180   440  48     0 100770
1023: 345 190   535  39     0 100770
1024: 450 295   745  65     0 100770
1025: 395 230   625  79     0 100770

这个data.table被命名为“analy”

我想缩放变量“LC”、“RC”、“TOEIC”、“eua”。 我可以按如下方式缩放

analy[,LC:=scale(LC)]
analy[,RC:=scale(RC)]
analy[,TOEIC:=scale(TOEIC)]
analy[,eua:=scale(eua)]

但是,我想知道如何一次缩放变量。

【问题讨论】:

    标签: r data.table scale


    【解决方案1】:
    analy[ , c("LC", "RC", "TOEIC", "eua") := lapply(list(LC, RC, TOEIC, eua), scale)] 
    

    一种更方便的方法是(正如@David 在评论中提到的那样):

    cols <- c("LC", "RC", "TOEIC", "eua")
    analy[, (cols) := lapply(.SD, scale), .SDcols=cols]
    

    注意cols 周围的( 是必需的,以便评估cols 以获取列名,然后通过引用修改它们。这样我们仍然可以继续做:DT[ ,col := val]

    【讨论】:

    • analy[, c("LC", "RC", "TOEIC", "eua") := lapply(.SD, scale), .SDcols = c("LC", "RC", "TOEIC", "eua")] 会是更正确的做法
    • 我不认为使用上面建议的lapply 有效。它确实计算了一些东西,但是除了第一列之外的所有列都有问题。我不知道为什么,但我找到了解决方法 - 请参阅下面的可重现结果的答案。
    【解决方案2】:

    这与使用.SD 在此处发布的关于 data.table 中的预处理列的更一般的问题有关:Computing inter-value differences in data.table columns (with .SD) in R

    这是您问题的答案,如果您错误地使用scale() 函数会得到什么:

    DT <- data.table(K=c(rep(1,5),rep(2,5)), X=(1:10)^2, Y=2^(1:10))
    cols <- 2:3;  cols.d0 = paste0("d0.", names(DT)[cols])
    
    # Correct and incorrect use of scale() with data.table
    
    # Works for one column.
    DT[, d0_Y:= scale(Y), keyby=K][]
    
    # RUNS BUT GIVES WRONG RESULT! ==> returns 1:20 data.table!
    DT[, scale(.SD), keyby=K, .SDcols=cols][]
    
    # RUNS WITH WARNING AND GIVES WRONG RESULT! - d0.X is computed correctly, by d0.Y not (compare to d0_Y) !
    DT[, (cols.d0) := scale(.SD), keyby=K, .SDcols=cols][]
    >     K   X    Y       d0_Y        d0.X        d0.Y
       1: 1   1    2 -0.8525736 -1.03417538 -1.03417538
       ...
    
    # DOESN'T RUN ! - ERROR
    DT[, (cols.d0) := lapply(.SD, scale), keyby=K, .SDcols=cols][]
    
    # WORKS CORRECTLY AS DESIRED !
    DT[, (cols.d0) := lapply(.SD, function(x) as.vector(scale(x))), keyby=K, .SDcols=cols][] 
    

    【讨论】:

      【解决方案3】:

      以下答案有效。

      library(data.table)
      # Data 
      dt <- iris
      setDT(dt)
      
      # columns to apply the scale function
      cols <- colnames(dt)[-5]
      
      # standerdize
      dt[, (cols) := lapply(.SD, function(x) as.vector(scale(x))),
                                            by = Species, .SDcols = cols]
      

      由于scale 返回一个矩阵,as.vector 用于转换为向量。

      【讨论】: