优化矢量化操作的 R 代码

问题描述 投票:0回答:2

这是一段目前运行良好的 R 代码:

x
"numeric"
unit
"character"
digits
"numeric"

process <- function(x, unit, digits) { 
  if (unit == "$") {
    x <- comprss(x)
    } else {
      x <- reformat(x,digits)
      }
  } 

x <- mapply(process, x, unit, digits) 

我使用

mapply
因为我想将函数应用到向量
x
x
data.table
的一列,
unit
digits
也是,它们的长度都相同。

我可以对函数

comprss
reformat
进行向量化,并将它们与 x 上的条件布尔向量一起应用,但这是我的问题:

函数

comprss
reformat
都接受一个整数作为参数并返回一个字符。因此,对于矢量化函数,如果我应用第一个函数,x 的类会从
"numeric"
更改为
"character"
,并且不能再应用第二个函数,这就是为什么我使用
mapply
而不是矢量化函数。

但是这种方法并没有利用矢量化运算,而且速度相当慢。

r performance optimization data.table runtime
2个回答
1
投票

使用 dplyr,它比你的方法快得多(尽管很难猜测你的函数到底做了什么)

library(tidyverse)
library(stringi)
library(rbenchmark)

comprss <- function(x) {
  paste(x)
}

reformat <- function(x, digits){
  format(x,nsmall = digits)
}

process <- function(x, unit, digits) { 
  if (unit == "$") {
    x <- comprss(x)
  } else {
    x <- reformat(x,digits)
  }
} 

x <- runif(100000,1,20000)
unit <- stri_rand_strings(100000,1,"[$€]")
digits <- floor(runif(100000,1,10))
df <- data.frame(x,
                 unit,
                 digits)

benchmark("dplyr" = {
  y <- df %>% mutate(y = if_else(unit == "$", comprss(x), reformat(x, digits))) %>% pull(y)
},
"question" = {
  y <- mapply(process, x, unit, digits)
},
replications = 5)
      test replications elapsed relative user.self sys.self user.child sys.child
1    dplyr            5    0.86    1.000      0.83     0.00         NA        NA
2 question            5    5.94    6.907      5.67     0.08         NA        NA

这是您作为 dplyr 的过程函数

if_else
:

y <- df %>% mutate(y = if_else(unit == "$", comprss(x), reformat(x, digits))) %>% pull(y)

0
投票

既然您询问了,那么是的,按组更改列的类不会很好地工作:

library(data.table)
MT <- as.data.table(head(mtcars))
MT[, disp := paste("qq", disp), by = cyl]
# Warning in `[.data.table`(MT, , `:=`(disp, paste("qq", disp)), by = cyl) :
#   Coercing 'character' RHS to 'double' to match the type of the target column (column 0 named '').
# Warning in `[.data.table`(MT, , `:=`(disp, paste("qq", disp)), by = cyl) :
#   NAs introduced by coercion
# Warning in `[.data.table`(MT, , `:=`(disp, paste("qq", disp)), by = cyl) :
#   Coercing 'character' RHS to 'double' to match the type of the target column (column 0 named '').
# Warning in `[.data.table`(MT, , `:=`(disp, paste("qq", disp)), by = cyl) :
#   NAs introduced by coercion
# Warning in `[.data.table`(MT, , `:=`(disp, paste("qq", disp)), by = cyl) :
#   Coercing 'character' RHS to 'double' to match the type of the target column (column 0 named '').
# Warning in `[.data.table`(MT, , `:=`(disp, paste("qq", disp)), by = cyl) :
#   NAs introduced by coercion

但是您可以通过分配给新的或已经是字符串(一次性)列然后重新分配来实现:

MT[, disp2 := paste("qq", disp), by = cyl][, disp := disp2][, disp2 := NULL][]
#      mpg   cyl   disp    hp  drat    wt  qsec    vs    am  gear  carb
#    <num> <num> <char> <num> <num> <num> <num> <num> <num> <num> <num>
# 1:  21.0     6 qq 160   110  3.90 2.620 16.46     0     1     4     4
# 2:  21.0     6 qq 160   110  3.90 2.875 17.02     0     1     4     4
# 3:  22.8     4 qq 108    93  3.85 2.320 18.61     1     1     4     1
# 4:  21.4     6 qq 258   110  3.08 3.215 19.44     1     0     3     1
# 5:  18.7     8 qq 360   175  3.15 3.440 17.02     0     0     3     2
# 6:  18.1     6 qq 225   105  2.76 3.460 20.22     1     0     3     1

就你而言,我认为是

DT[, x2 := mapply(process, x, unit, digits), by = yourgroup
  ][, x := x2][, x2 := NULL]
© www.soinside.com 2019 - 2024. All rights reserved.