[英]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]
這是使用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
),滾動連接將找到那些小於b
a
。 將sum(n - cs)
替換為包含求和符號的數學公式,使得sum(constant)
= summation * constant 中的元素數。
output:
[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
在某種程度上,它類似於MattB 的方法,但在非等值連接中結合了笛卡爾積CJ()
和子集,從而避免創建隨后將被過濾掉的數據。
請注意, x.
從第一個 data.table 中選擇a
列需要前綴。
或者, sum(ib - xa)
可以重寫為.N * b - sum(xa)
其中特殊符號.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
帶有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
像這樣的東西?
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.