向量中所有小于另一个向量的值的差的总和

3

我有以下代码来循环遍历序列并选择序列中低于这些值的值,并查找与另一个值的差异。对于大型数据集,这可能需要很长时间。有没有一种方式可以向量化这样的操作,而不必通过循环遍历序列来提高性能?

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]
4个回答

3

这里提供了一种使用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将找到那些小于 ba。用涉及求和符号的数学公式替换 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

我使用了这个答案,但需要一个非等值连接。我使用了:fin <- A[B, on=.(a<b), mult="last", N * b - cs] 并将NA值设置为零:fin[is.na(fin)] <- 0 - at80

3
使用 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

从某种意义上说,它类似于 MattB 的方法,但结合了笛卡尔积CJ()和非等值连接中的子集操作,从而避免创建将被后续过滤掉的数据。

请注意,使用前缀 x. 选取第一个数据表中的 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

2
使用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

1
像这样的东西?
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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接