将一个向量中小于另一个向量中的值的所有值的差相加

Summing the difference of all values of one vector that are less than the values in another

我在下面有以下代码尝试循环遍历序列和序列中这些值下方的 select 值,并找到与另一个值的差异。对于大型数据集,这可能需要很长时间。有没有一种方法可以在不循环遍历序列的情况下对这样的东西进行矢量化以提高性能?

a <- seq(1, 10, by=0.25)
b <- seq(1, 10, by=1)

c <- vector('list', length(b))

i <- 1
for (n in b){
    c[[i]] <- sum(n - a[n >= a])
    i <- i + 1
}

data.frame(c)

我尝试使用 data.table 对数据进行分箱并找出差异,但无法弄清楚如何计算每个小于分箱值的值的差异。

library(data.table)

min.n <- 1
max.n <- 10 
a <- data.table(seq(min.n, max.n, by=0.5))
colnames(a) <- 'a'
b <- seq(min.n+1, max.n+1, by=1)

bins <- findInterval(a$a,b)
a[,bins:= bins+2]
a[, diff:= bins - a]

是这样的吗?

library(data.table)
a <- seq(1, 10, by=0.25)
b <- seq(1, 10, by=1)

all.combinations <- CJ(a, b)  # Get all possible combinations
all.combinations[b>=a, sum(b-a), by=b]  # Filter for b>=a, then sum the difference for each value of b

具有 findInterval 的基础 R 解决方案,速度很快。

i <- findInterval(b, a)
sapply(seq_along(i), function(j)sum(b[j] - a[1:i[j]]))
# [1]   0.0   2.5   9.0  19.5  34.0  52.5  75.0 101.5 132.0 166.5

这是一个使用 data.table 滚动连接的选项:

library(data.table)
A <- data.table(a, key="a")
B <- data.table(b, key="b")

A[, c("N", "cs") := .(.I, cumsum(a))]

A[B, on=.(a=b), roll=Inf, N * b - cs]

sum a[a <= n]可以用cumsum代替(即这里的cs),rolling join会找到那些a小于b的。将 sum(n - cs) 替换为涉及求和符号的数学公式,以便 sum(constant) = 求和中的元素数 * 常数。

输出:

[1]   0.0   2.5   9.0  19.5  34.0  52.5  75.0 101.5 132.0 166.5

编辑:一些时间参考

时间码:

set.seed(0L)
library(data.table)
n <- 1e5L
a <- rnorm(n)
b <- rnorm(n/10L)
A <- data.table(a, key="a")
B <- data.table(b, key="b")

mtd0 <- function() A[B, on = .(a <= b), sum(i.b - x.a), by = .EACHI]$V1

mtd1 <- function() {
    A[, c("N", "cs") := .(.I, cumsum(a))]
    A[B, on=.(a=b), roll=Inf, N * b - cs]
}

all.equal(mtd0(), mtd1())
#[1] TRUE

microbenchmark::microbenchmark(times=1L, mtd0(), mtd1())

时间安排:

Unit: milliseconds
   expr         min          lq        mean      median          uq         max neval
 mtd0() 2998.208000 2998.208000 2998.208000 2998.208000 2998.208000 2998.208000     1
 mtd1()    7.807637    7.807637    7.807637    7.807637    7.807637    7.807637     1

使用 data.table,这可以通过 在非等值连接中聚合来实现 :

library(data.table)
data.table(a)[data.table(b), on = .(a <= b), sum(i.b - x.a), by = .EACHI]$V1
[1]   0.0   2.5   9.0  19.5  34.0  52.5  75.0 101.5 132.0 166.5

在某种程度上,它类似于 ,但在 non-equi join 中结合了笛卡尔积 CJ() 和子集,从而避免创建后续过滤掉的数据。

请注意,需要 x. 前缀才能从第一个 data.table 中选择 a 列。


或者,sum(i.b - x.a) 可以重写为 .N * b - sum(x.a),其中特殊符号 .N 表示组中的行数。

data.table(a)[data.table(b), on = .(a <= b), .N * b - sum(x.a), by = .EACHI]$V1
[1]   0.0   2.5   9.0  19.5  34.0  52.5  75.0 101.5 132.0 166.5