除了使用R base函数以外,是否有一种有效的方法来获得“ pmax”?

费尔南多·布里托·洛佩斯

我想使用Rcpp创建一个函数,该函数可能优于R base的pmax函数。我还尝试处理Rcpp函数内部的缺失值,这可能不是一个好主意。所有向量都必须具有一些缺失值,并且它们都是正值。这就是我将缺少的代码重新编码为-1的原因,因此,如果所有值都丢失,则最大值不存在时,我可以将其重新添加。

这是我的第一次尝试,但尚未成功:

library("benchr")
library("Rcpp")

Pmax <- function(...) {
  argd_list <- list(...)
  cppFunction("
  NumericVector cpp_pmax(List args) {
    List args0 = args[0];
    int n_arg = args.length();
    int n_vec = args0.length();
    NumericVector out(n_vec);
    out = args[0];
    for (int i = 1; i < n_arg; ++i) {
        NumericVector pa(n_vec);
        pa = args[i];
        for (int j = 0; j < n_vec; ++j) {
          if (R_IsNA(out[j])) {
            out[j] = -1;
          }
          if (R_IsNA(pa[j])) {
            pa[j] = -1;
          }
          out[j] = std::max(out[j], pa[j]);
        }
    }
    for (int j = 0; j < n_vec; ++j) {
      if (out[j] == -1) {
        out[j] = NA_REAL;
      }
    }
    return out;
  }
")
  output <- cpp_pmax(argd_list)
  return(output)
}


n <- 200000
x1 <- sample(0:1, n, replace = TRUE)
y1 <- sample(0:1, n, replace = TRUE)
z1 <- sample(0:1, n, replace = TRUE)
x1[sample(1:n, 90)]<-NA
y1[sample(1:n, 60)]<-NA
z1[sample(1:n, 70)]<-NA

pm1 <- Pmax(x1, y1, z1)
pm2 <- pmax(x1, y1, z1, na.rm = TRUE)

all(pm1 == pm2)

benchr::benchmark(pmax(x1, y1, z1, na.rm = TRUE),
                  Pmax(x1, y1, z1))

Benchmark summary:
  Time units : milliseconds 
expr                           n.eval   min lw.qu median  mean up.qu   max total relative
pmax(x1, y1, z1, na.rm = TRUE)    100  1.34  1.37   1.39  1.44  1.46  1.74   144     1.00
Pmax(x1, y1, z1)                  100 13.30 13.50  13.80 19.90 15.70 67.50  1990     9.88

编辑:

我删除了一些循环,只是在Rcpp之外用NA代替了-1,它加快了一点,但仍不胜过R base pmax。

尽管Rcpp :: pmax是一个不错的实现,但它仅处理两个向量,不确定是否可以处理缺失的值。缺少价位时,我得到了不同的结果。

第二次尝试是:

Pmax1 <- function(...) {
  args_list <- list(...)
  cppFunction("
  NumericVector cpp_pmax(List args) {
    List args0 = args[0];
    int n_arg = args.length();
    int n_vec = args0.length();
    NumericVector out(n_vec);
    out = args[0];
    for (int i = 1; i < n_arg; ++i) {
        NumericVector pa(n_vec);
        pa = args[i];
        for (int j = 0; j < n_vec; ++j) {
          if (R_IsNA(out[j])) {
            out[j] = -1;
          }
          if (R_IsNA(pa[j])) {
            pa[j] = -1;
          }
          out[j] = std::max(out[j], pa[j]);
        }
    }
    return out;
  }
")
  output <- cpp_pmax(args_list)
  output[output == -1] <- NA
  return(output)
}

Pmax2 <- function(...) {
  args_list <- list(...)
  cppFunction("
  NumericVector cpp_pmax(List args) {
    NumericVector out = args[0];
    int n_arg = args.length();
    int n_vec = out.length();
    for (int j = 0; j < n_vec; ++j) {
      if (NumericVector::is_na(out[j])) out[j] = -1;
    }
    for (int i = 1; i < n_arg; ++i) {
      NumericVector pa = args[i];
      for (int j = 0; j < n_vec; ++j) {
        if (NumericVector::is_na(pa[j])) pa[j] = -1;
        out[j] = std::max(out[j], pa[j]);
      }
    }
    return out;
  }
")
  output <- cpp_pmax(args_list)
  output[output == -1] <- NA
  return(output)
}

n <- 200000
x <- sample(0:5, n, replace = TRUE)
y <- sample(0:5, n, replace = TRUE)
z <- sample(0:5, n, replace = TRUE)
w <- sample(0:5, n, replace = TRUE)
x[sample(1:n, 900)]<-NA
y[sample(1:n, 600)]<-NA
z[sample(1:n, 700)]<-NA
z[sample(1:n, 800)]<-NA

benchr::benchmark(pmax(x,  y, z, w, na.rm = TRUE),
                  Pmax1(x,  y, z, w),
                  Pmax2(x, y, z, w))

Benchmark summary:
  Time units : milliseconds 
                          expr n.eval   min lw.qu median  mean up.qu  max total relative
pmax(x, y, z, w, na.rm = TRUE)    100  2.38  2.43   2.46  2.46  2.48  2.6   246     1.00
Pmax1(x, y, z, w)                 100 16.00 16.90  17.20 19.40 17.70 61.2  1940     6.98
Pmax2(x, y, z, w)                 100  9.44  9.74   9.90 11.30 10.10 45.6  1130     4.02

有谁知道如何使其比R base pmax更快?

想法是在Rcpp函数内部都具有一个通用函数来处理不同数量的向量。

基于@DirkEddelbuettel和@Cole的更新

感谢您帮助优化代码。受@DirkEddelbuettel和@Cole的启发,我只添加了Rcpp :: pmax即可删除其中一个循环,它也有助于加快循环速度。

library("bench")
library("Rcpp")

cppFunction("
  IntegerVector cpp_pmax1(List args) {
    IntegerVector tmp = args[0];
    IntegerVector out = clone(tmp);
    int n_arg = args.length();
    int n_vec = out.length();
    for (int i = 1; i < n_arg; ++i) {
      IntegerVector pa = args[i];
      for (int j = 0; j < n_vec; ++j) {
        if (pa[j] > out[j]) out[j] = pa[j];
      }
    }
    return out;
  }
")

cppFunction("
  IntegerVector cpp_pmax2(List args) {
    IntegerVector tmp = args[0];
    IntegerVector out = clone(tmp);
    int n_arg = args.length();
    int n_vec = out.length();
    for (int i = 1; i < n_arg; ++i) {
      IntegerVector pa = args[i];
      out = pmax(out, pa);
    }
    return out;
  }
")

Pmax1 <- function(...) {
  cpp_pmax1(list(...))
}


Pmax2 <- function(...) {
  cpp_pmax2(list(...))
}


n <- 200000
x <- sample(0:5, n, replace = TRUE)
y <- sample(0:5, n, replace = TRUE)
z <- sample(0:5, n, replace = TRUE)
w <- sample(0:5, n, replace = TRUE)
k <- sample(0:5, n, replace = TRUE)
x[sample(1:n, 900)] <- NA
y[sample(1:n, 600)] <- NA
z[sample(1:n, 700)] <- NA
w[sample(1:n, 800)] <- NA
k[sample(1:n, 800)] <- NA

pm0 <- pmax(x,  y, z, w, k, na.rm = TRUE)
pm1 <- Pmax1(x, y, z, w, k)
pm2 <- Pmax2(x, y, z, w, k)

benchr::benchmark(pmax(x,  y, z, w, k, na.rm = TRUE),
                  Pmax1(x, y, z, w, k),
                  Pmax2(x, y, z, w, k))


Benchmark summary:
  Time units : microseconds 
                             expr n.eval  min lw.qu median mean up.qu  max  total relative
pmax(x, y, z, w, k, na.rm = TRUE)    100 2880  2900   2920 3050  3080 8870 305000     5.10
Pmax1(x, y, z, w, k)                 100 2150  2180   2200 2310  2350 8060 231000     3.85
Pmax2(x, y, z, w, k)                 100  527   558    572  812   719 7870  81200     1.00
  

谢谢!

油菜

bench::mark发现中可以看出,似乎存在一些内存分配问题

bench::mark(pmax(x,  y, z, w, na.rm = TRUE),
            Pmax2(x, y, z, w))

## # A tibble: 2 x 13
##   expression                         min  median `itr/sec` mem_alloc
##   <bch:expr>                     <bch:t> <bch:t>     <dbl> <bch:byt>
## 1 pmax(x, y, z, w, na.rm = TRUE)  5.79ms  6.28ms     157.    781.3KB
## 2 Pmax2(x, y, z, w)              39.56ms 54.48ms      19.7    9.18MB

记忆胁迫

与base相比,内存分配是其10倍pmax()您的是相对简单的,因此这暗示着某种强制。在查看样本数据时,您正在将整数向量发送到数字签名。这产生了昂贵的强制。让我们更新期望IntegerVector签名和代码我只是将所有内容从NumericVector更改IntegerVector为。

  expression                         min  median `itr/sec` mem_alloc
  <bch:expr>                     <bch:t> <bch:t>     <dbl> <bch:byt>
1 pmax(x, y, z, w, na.rm = TRUE)  1.89ms  2.33ms     438.    781.3KB
2 Pmax2_int(x, y, z, w)          37.42ms 49.88ms      17.6    2.32MB

重新编译

OP代码包含cppFunction在较大的功能代码中。除非我们需要在每个循环中重新编译它,否则我们可以编译然后从R中调用已编译的代码。这是此数据集大小最大的性能提升。

cppFunction("
  IntegerVector cpp_pmax_pre(List args) {
    IntegerVector out = args[0];
    int n_arg = args.length();
    int n_vec = out.length();
    for (int j = 0; j < n_vec; ++j) {
      if (IntegerVector::is_na(out[j])) out[j] = -1;
    }
    for (int i = 1; i < n_arg; ++i) {
      IntegerVector pa = args[i];
      for (int j = 0; j < n_vec; ++j) {
        if (IntegerVector::is_na(pa[j])) pa[j] = -1;
        out[j] = std::max(out[j], pa[j]);
      }
    }
    return out;
  }
")

Pmax2_int_pre <- function(...) {
  args_list <- list(...)
  output <- cpp_pmax_pre(args_list)
  output[output == -1] <- NA
  return(output)
}

bench::mark(pmax(x,  y, z, w, na.rm = TRUE),
            Pmax2_int_pre(x, y, z, w))

## # A tibble: 2 x 13
##   expression                        min median `itr/sec` mem_alloc
##   <bch:expr>                     <bch:> <bch:>     <dbl> <bch:byt>
## 1 pmax(x, y, z, w, na.rm = TRUE) 2.31ms 2.42ms      397.   781.3KB
## 2 Pmax2_int_pre(x, y, z, w)      2.48ms 3.55ms      270.    2.29MB

更多的内存和小的优化

最后,我们还有更多的内存分配。这暗示我们可以做更多的事情-在这种情况下,我们应该NA_REAL更新相关的,我们可以优化循环分配一些。

cppFunction("
  IntegerVector cpp_pmax_final(List args) {
    IntegerVector out = args[0];
    int n_arg = args.length();
    int n_vec = out.length();
    for (int j = 0; j < n_vec; ++j) {
      if (IntegerVector::is_na(out[j])) out[j] = -1;
    }
    for (int i = 1; i < n_arg; ++i) {
      IntegerVector pa = args[i];
      for (int j = 0; j < n_vec; ++j) {
// simplify logic; if the element is not na and is greater than the out, update out.
        if (!IntegerVector::is_na(pa[j]) & pa[j] > out[j]) out[j] = pa[j];
      }
    }
// update now in Rcpp instead of allocating vectors in R
    for (int i = 0; i < n_vec; i++) {
      if(out[i] == -1) out[i] = NA_INTEGER;
    }
    return out;
  }
")

Pmax2_final <- function(...) {
  cpp_pmax_final(list(...))
}

bench::mark(pmax(x,  y, z, w, na.rm = TRUE),
            Pmax2_final(x, y, z, w))

## # A tibble: 2 x 13
##   expression                        min median `itr/sec` mem_alloc
##   <bch:expr>                     <bch:> <bch:>     <dbl> <bch:byt>
## 1 pmax(x, y, z, w, na.rm = TRUE)    2ms 2.08ms      460.   781.3KB
## 2 Pmax2_final(x, y, z, w)        1.19ms 1.45ms      671.    2.49KB

我们做到了*!我确信可能会有一些小的优化-我们访问了pa[j]3次,因此可能值得分配一个变量。

奖金-NA_INTEGER

根据Rcpp for Everyone,该值NA_INTEGER应等于-2147483648的最低整数值。使用此方法,我们可以删除NA的替换,因为在处理int数据类型时可以直接与NA进行比较

在此实现过程中,我还发现了上一部分的问题-我们需要克隆初始参数,以免意外地通过引用更改它。尽管如此,我们仍然比base稍快pmax()

cppFunction("
  IntegerVector cpp_pmax_last(List args) {
    IntegerVector tmp = args[0];
    IntegerVector out = clone(tmp);
    int n_arg = args.length();
    int n_vec = out.length();
    for (int i = 1; i < n_arg; ++i) {
      IntegerVector pa = args[i];
      for (int j = 0; j < n_vec; ++j) {
        if (pa[j] > out[j]) out[j] = pa[j];
      }
    }
    return out;
  }
")

Pmax2_last <- function(...) {
  cpp_pmax_last(list(...))
}

bench::mark(pmax(x,  y, z, w, na.rm = TRUE),
            Pmax2_last(x, y, z, w),
)

## # A tibble: 2 x 13
##   expression                        min median `itr/sec` mem_alloc `gc/sec`
##   <bch:expr>                     <bch:> <bch:>     <dbl> <bch:byt>    <dbl>
## 1 pmax(x, y, z, w, na.rm = TRUE) 5.98ms 6.36ms      154.     781KB        0
## 2 Pmax2_last(x, y, z, w)         5.09ms 5.46ms      177.     784KB        0

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

R:pmax()函数忽略NA?

来自分类Dev

r:使用pmax函数忽略NA值

来自分类Dev

缩小HTML时,是否存在一种有效的方法来在列表项之间强制使用空格?

来自分类Dev

缩小HTML时,是否存在一种有效的方法来在列表项之间强制使用空格?

来自分类Dev

除了NumPy矩阵中的特定列,是否有一种有效的方法来获取max元素的位置?

来自分类Dev

R:是否有一种简单有效的方法来获取块对角矩阵的构建矩阵列表?

来自分类Dev

R:是否有一种简单有效的方法来获取块对角矩阵的构建矩阵列表?

来自分类Dev

一种有效的方法来对R中的组内行的子集进行分组然后应用功能

来自分类Dev

需要一种有效的方法来避免使用Laravel 5重复代码片段

来自分类Dev

寻找一种更有效的方法来使用 STL 函数检查字符串是否为回文

来自分类Dev

有没有一种有效的方法来将redux与react一起使用而没有react-redux?

来自分类Dev

有没有一种有效的方法来覆盖Appengine实体中的get()和put()方法,以使其使用内存缓存?

来自分类Dev

有没有一种更快的方法来检查文件是否正在使用?

来自分类Dev

数据转换:我正在寻找R中一种有效的方法来重新编码/扩展多对一生存分析

来自分类Dev

是否有一种方法来获取R中不同列的频率分布

来自分类Dev

是否有一种有效的方法可以向后搜索R中的大矢量?

来自分类Dev

有没有一种快速的方法来在Python中获得ls()的R等效项?

来自分类Dev

返回具有多个列的data.frame的pmin或pmax

来自分类Dev

如何为列使用范围而不是pmax / pmin的名称

来自分类Dev

CGDisplayCopyAllDisplayModes排除了一种有效模式

来自分类Dev

使用Velocity变量时,是否有一种紧凑的方法来设置默认值(如Freemarker方法)?

来自分类Dev

是否有一种高效快捷的方法来覆盖 TreeSet 中使用的 compareTo() 方法

来自分类Dev

有没有一种简单的方法来限制用户带宽的使用?

来自分类Dev

有没有一种简单的方法来限制用户带宽的使用?

来自分类Dev

除了使用Bash(通过cron作业查找)以外,还有一种更好的方法来删除文件,只要它们变旧5分钟就可以了?

来自分类Dev

有没有一种棘手的方法来避免覆盖模板基类的所有纯虚函数,这些函数在多重继承中使用

来自分类Dev

R中是否有一种有效的方法可以将矩阵M2的每一行“粘贴”到矩阵M1的每一行以获得所有可能的组合?

来自分类Dev

有一种意识形态的方法来避免使用Naked New吗?

来自分类Dev

这是一种有效的方法,用于查看是否在javascript中使用php设置了2个cookie

Related 相关文章

  1. 1

    R:pmax()函数忽略NA?

  2. 2

    r:使用pmax函数忽略NA值

  3. 3

    缩小HTML时,是否存在一种有效的方法来在列表项之间强制使用空格?

  4. 4

    缩小HTML时,是否存在一种有效的方法来在列表项之间强制使用空格?

  5. 5

    除了NumPy矩阵中的特定列,是否有一种有效的方法来获取max元素的位置?

  6. 6

    R:是否有一种简单有效的方法来获取块对角矩阵的构建矩阵列表?

  7. 7

    R:是否有一种简单有效的方法来获取块对角矩阵的构建矩阵列表?

  8. 8

    一种有效的方法来对R中的组内行的子集进行分组然后应用功能

  9. 9

    需要一种有效的方法来避免使用Laravel 5重复代码片段

  10. 10

    寻找一种更有效的方法来使用 STL 函数检查字符串是否为回文

  11. 11

    有没有一种有效的方法来将redux与react一起使用而没有react-redux?

  12. 12

    有没有一种有效的方法来覆盖Appengine实体中的get()和put()方法,以使其使用内存缓存?

  13. 13

    有没有一种更快的方法来检查文件是否正在使用?

  14. 14

    数据转换:我正在寻找R中一种有效的方法来重新编码/扩展多对一生存分析

  15. 15

    是否有一种方法来获取R中不同列的频率分布

  16. 16

    是否有一种有效的方法可以向后搜索R中的大矢量?

  17. 17

    有没有一种快速的方法来在Python中获得ls()的R等效项?

  18. 18

    返回具有多个列的data.frame的pmin或pmax

  19. 19

    如何为列使用范围而不是pmax / pmin的名称

  20. 20

    CGDisplayCopyAllDisplayModes排除了一种有效模式

  21. 21

    使用Velocity变量时,是否有一种紧凑的方法来设置默认值(如Freemarker方法)?

  22. 22

    是否有一种高效快捷的方法来覆盖 TreeSet 中使用的 compareTo() 方法

  23. 23

    有没有一种简单的方法来限制用户带宽的使用?

  24. 24

    有没有一种简单的方法来限制用户带宽的使用?

  25. 25

    除了使用Bash(通过cron作业查找)以外,还有一种更好的方法来删除文件,只要它们变旧5分钟就可以了?

  26. 26

    有没有一种棘手的方法来避免覆盖模板基类的所有纯虚函数,这些函数在多重继承中使用

  27. 27

    R中是否有一种有效的方法可以将矩阵M2的每一行“粘贴”到矩阵M1的每一行以获得所有可能的组合?

  28. 28

    有一种意识形态的方法来避免使用Naked New吗?

  29. 29

    这是一种有效的方法,用于查看是否在javascript中使用php设置了2个cookie

热门标签

归档