分类整数数据的最快方法

时间:2015-07-02 13:27:56

标签: r

我在下表中给出了一个映射:

beforeInitGrid: function () {
    var $self = $(this), p = $self.jqGrid("getGridParam"),
        yItems = p.pivotOptions.yIndex.items, matches, iy, y,
        colModel = p.colModel, i, cm, l = colModel.length, cmName;

    for (i = 0; i < l; i++) {
        cm = colModel[i];
        cmName = cm.name;
        if (cmName.charAt(0) === "y") { // x, y, t
            // aggregation column
            matches = /^([x|y])(\d+)(t(\d+))?(a)?(\d+)/.exec(cmName);
            if (matches !== null && matches.length > 1) {
                // matches[2] - iy - index if y item
                // matches[4] - undefined or total group index
                // matches[6] - ia - aggregation index
                iy = parseInt(matches[2], 10);
                y = yItems[iy];
                if (y != null && (y[0] === "2015" || (y[0] === "2011" && y[1] === "7"))) {
                    cm.hidden = true;
                }
            }
        }
    }
}

到现在为止,我写了3个版本:

Class[] classes = new Class[3];
classes[0] = Activity0.class;
classes[1] = Activity1.class;
classes[2] = Activity2.class;
Random r = new Random();

Intent i = new Intent(this, classes[r.nextInt(classes.length)]);
startActivity(i);

第二

Input  Output
<4     0
5      0.4
6      0.5
7      0.65
8      0.75
9      0.85
>=10   1

第三

k1 <- function(h) {
  if (h <= 4) { k <- 0
  } else if (h == 5) { k <- 0.4
  } else if (h == 6) { k <- 0.5
  } else if (h == 7) { k <- 0.65
  } else if (h == 8) { k <- 0.75
  } else if (h == 9) { k <- 0.85
  } else if (h >= 10) { k <- 1}
  return(k)
}

我需要在两种不同场景中使用该功能。 首先,评估标量输入,然后评估值的向量。

对于标量输入:

k2 <- function(h) {
  k <- 0
  k[h == 5] <- 0.4
  k[h == 6] <- 0.5
  k[h == 7] <- 0.65
  k[h == 8] <- 0.75
  k[h == 9] <- 0.85
  k[h >= 10] <- 1.0
  return(k)
}

对于矢量输入:

k3 <- function(h) {
  k <- cut(h, breaks=c(0, 5, 6, 7, 8, 9, Inf), labels=c(0, 0.5, 0.65, 0.75, 0.85, 1), right=FALSE)  
  return(k)
}

因此,标量输入的k1最快,矢量输入的k2最快。

你认为有可能提高速度吗?我无法相信这样一个笨拙的if / else代码在标量情况下应该是最快的。 此外,我希望有一个统一的功能,而不是两个单独的功能。

2 个答案:

答案 0 :(得分:8)

首先,为什么要在标量输入上优化几个微秒?如果答案是&#34;因为必须多次,多次调用标量版本,&#34;也许是在一个循环中,而不是那个问题;操作应该是矢量化的。 (请注意,k2可以在k1仅处理15个时间内处理250个输入。

无论如何,另一种选择是:

outputs <- c(0, .4, .5, .65, .75, .85, 1)
k4 <- function(h) {
  output[pmin.int(pmax.int(h, 4), 10) - 3]
}

在我的系统中,这只是在向量化案例中绑定k2,但它在标量情况下的速度是k2的两倍:

h <- 5
microbenchmark(k1(h), k2(h), k3(h), k4(h))
# Unit: nanoseconds
#   expr   min      lq     mean  median      uq    max neval
#  k1(h)   748   933.5  1314.29  1181.5  1655.0   3091   100
#  k2(h)  4131  5424.5  6378.31  6236.5  7021.5  18140   100
#  k3(h) 72149 74495.0 79796.22 75716.0 80936.5 176857   100
#  k4(h)  1730  2259.5  3396.04  3338.5  3801.0  17001   100

h <- rep(5, 250)
microbenchmark(sapply(h, k1), k2(h), k3(h), k4(h))
# Unit: microseconds
#           expr     min       lq      mean   median       uq     max neval
#  sapply(h, k1) 311.099 327.5710 341.05200 335.9330 348.6405 405.830   100
#          k2(h)  13.973  18.4965  20.64351  20.4160  22.4015  34.289   100
#          k3(h) 117.401 125.0180 134.49228 129.2455 138.8240 241.896   100
#          k4(h)  15.042  17.8870  20.33141  19.0690  20.4260  37.386   100

它也比k2更简洁,更容易扩展到更多的整数输入。

最后,如果您愿意依赖Rcpp,相对于k2k4,您可以获得5倍的加速:

library(Rcpp)
cppFunction('NumericVector k5(IntegerVector h) {
              int n = h.size();
              NumericVector out(n);

              for (int i = 0; i < n; ++i) {
                int val = h[i];
                if (val <= 4) out[i] = 0;
                else if (val == 5) out[i] = .4;
                else if (val == 6) out[i] = .5;
                else if (val == 7) out[i] = .65;
                else if (val == 8) out[i] = .75;
                else if (val == 9) out[i] = .85;
                else if (val >= 10) out[i] = 1;
              }
              return out;
            }')

h <- rep(5, 250)
microbenchmark(sapply(h, k1), k2(h), k3(h), k4(h), k5(h))

# Unit: microseconds
#           expr     min       lq      mean   median       uq     max neval
#  sapply(h, k1) 382.383 410.7310 429.88844 423.7150 442.5765 501.400   100
#          k2(h)  17.129  20.5865  23.95221  22.1340  23.7915  46.827   100
#          k3(h) 123.519 127.6830 142.24084 140.5400 150.1525 218.919   100
#          k4(h)  15.168  18.2705  20.45797  19.1985  20.6105  52.650   100
#          k5(h)   2.988   4.9045   6.49218   5.9135   6.8455  33.219   100

(参见&#34;矢量输入,矢量输出&#34;此Rcpp intro部分作为这些功能的指南)。但请注意,它在标量情况下仍然比k1慢2倍!

答案 1 :(得分:7)

findInterval是R中最快的功能。

out <- c(0, .4, .5, .65, .75, .85, 1)
k6 <- function(h){
    ind <- findInterval(h, c(4, 5, 6, 7, 8, 9) +0.1) + 1
    out[ind]
}

h <- rep(5, 250)
microbenchmark(k2(h), k4(h), k6(h), unit="relative")
Unit: relative
#  expr      min       lq     mean   median       uq      max neval
# k2(h) 2.283983 2.347714 2.225037 2.392578 2.319125 1.184224   100
# k4(h) 1.830939 1.725286 1.699866 1.701196 1.599973 1.414026   100
# k6(h) 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000   100