R 突变速度非常慢

R 突变速度非常慢,r,dplyr,R,Dplyr,我正在处理产生光谱的仪器产生的数据。这意味着每个数据点有3201个元素长。我想通过减去中位数或使用scale不时对数据进行标准化。我的数据与其他变量不兼容,因此我想使用dplyr中的mutate_at函数,但这似乎需要非常长的时间 set.seed(123) ## generate some test data ncol = 100 d_f = data.frame(color = rep('C', 5), rep = factor(1:5),

我正在处理产生光谱的仪器产生的数据。这意味着每个数据点有3201个元素长。我想通过减去中位数或使用
scale
不时对数据进行标准化。我的数据与其他变量不兼容,因此我想使用
dplyr
中的
mutate_at
函数,但这似乎需要非常长的时间

set.seed(123)
## generate some test data
ncol = 100
d_f = data.frame(color = rep('C', 5), 
                 rep = factor(1:5), 
                 matrix(rnorm(5 * ncol), nrow = 5))
d_f = as.tibble(d_f)

sc1 = function(x, scale =  c("med", "z")){
  scale = match.arg(scale)

  if(scale == 'med'){
     x = x %>% mutate_at(vars(matches("^X[0-9]+$")), funs(. - median(.)))
  }else if(scale == 'z'){
    x = x %>% mutate_at(vars(matches("^X[0-9]+$")), funs(base::scale))
  }
}

sc2 = function(x, scale = c("med", "z")){

  scale = match.arg(scale)

  y = x %>% select(matches("^X[0-9]+$")) %>% as.matrix()

  if(scale == 'med'){
    y = sweep(y, 2, apply(y, 2, median))
  }else if(scale == 'z'){
    y = base::scale(y)
  }

  y = as.tibble(y)
  names(y) = paste0("X", 1:ncol)
  x = x %>% select(matches("^[^X].*$")) %>% bind_cols(y)
  return(x)
}

microbenchmark(d_f %>% sc1, d_f %>% sc2)
以下是100列的结果:

Unit: milliseconds
        expr      min        lq      mean    median        uq       max neval cld
  d_f %>% sc1 142.1663 157.08819 188.71257 174.88702 209.38378 441.79132   100   b
  d_f %>% sc2  12.6180  15.17256  18.83863  16.90944  20.11142  45.81297   100  a 
Unit: milliseconds
        expr       min        lq     mean   median       uq      max neval cld
 d_f %>% sc1 13.904984 15.975898 19.38772 17.34842 21.25275 40.98175   100   b
 d_f %>% sc2  8.817058  9.746072 11.74869 10.89266 12.93568 23.96279   100  a 
以下是仅包含10列的结果:

Unit: milliseconds
        expr      min        lq      mean    median        uq       max neval cld
  d_f %>% sc1 142.1663 157.08819 188.71257 174.88702 209.38378 441.79132   100   b
  d_f %>% sc2  12.6180  15.17256  18.83863  16.90944  20.11142  45.81297   100  a 
Unit: milliseconds
        expr       min        lq     mean   median       uq      max neval cld
 d_f %>% sc1 13.904984 15.975898 19.38772 17.34842 21.25275 40.98175   100   b
 d_f %>% sc2  8.817058  9.746072 11.74869 10.89266 12.93568 23.96279   100  a 

单次运行3201个
sc1
需要约72秒,因此减少了测试集

我的答案是
mutate_at()
的开销比从矩阵转换到矩阵的开销要大得多

下面是对
sc1()
的分析:

>summaryRprof()$by.self
self.time self.pct total.time total.pct
“乐趣”0.3419.540.9252.87
“makeActiveBinding”0.2413.790.4827.59
“lappy”0.20 11.49 0.88 50.57
“激活绑定”0.20 11.49 0.24 13.79
“sort.int”0.148.05 0.148.05
“吸血鬼”0.12 6.90 0.36 20.69
“%in%”0.04 2.30 0.14 8.05
“获取环境”0.04 2.30 0.10 5.75
“rm”0.04 2.30 0.06 3.45
"!"                            0.04     2.30       0.04      2.30
“力”0.04 2.30 0.04 2.30
。请致电“0.02 1.15 1.68 96.55”
“tryCatch”0.02 1.15 1.66 95.40
""                  0.02     1.15       1.48     85.06
"%||%"                         0.02     1.15       0.08      4.60
“0.02 1.15 0.06 3.45的”类型
“为空”0.02 1.15 0.04 2.30
"=="                           0.02     1.15       0.02      1.15
“全部”0.02 1.15 0.02 1.15
“任何”0.02 1.15 0.02 1.15
“as.character”0.02 1.15 0.02 1.15
“继承”0.02 1.15 0.02 1.15
“是否公式化”0.02 1.15 0.02 1.15
“is.null”0.02 1.15 0.02 1.15
“名称”0.02 1.15 0.02 1.15
“系统调用”0.02 1.15 0.02 1.15

这两个函数的结果不一样。他们似乎对我做的事情不一样。您在这里比较的是什么?您至少希望
应用(y,2,median)
来获取列中位数,而不是行中位数。但我的猜测是,90%的差异是因为处理矩阵比处理数据帧更快。谢谢@Gregor-这里有一个小错误,我已经纠正了它。@Psidom-是的,他们现在也这么做了。目的已在上文中解释。我希望通过减去列中间值或减去列平均值并除以列标准偏差来标准化行。我认为这是完全正确的,但要真正做到这一点,您应该与
sc2()
的配置文件进行比较。我同意。我应该包括这一点来真正说明问题(我做了分析)。我也做了分析,但无法了解输出的正反两面。