You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

优化data.table中HR斜率与自定义累积和的高效无循环实现方案

Efficient Calculation of HRSlope and HRCumsum in data.table

Hey there! Let's fix those slow loop-based calculations for your large data.table. We'll use data.table's built-in fast grouping and rolling window functions to avoid loops entirely, which should give you a massive speedup.

First, let's recap your data and requirements

Your input data looks like this:

library(data.table)
allData <- data.table(nightNo=c(1,1,1,1,1,1,2,2,2,2), 
                      withinNightNo=c(1,2,3,4,5,6,1,2,3,4), 
                      HR=c(1:10))

You need two new columns:

  1. HRSlope: Linear regression slope of HR vs withinNightNo using the most recent 10 rows (or all prior rows if less than 10) within the same nightNo.
  2. HRCumsum: Custom cumulative sum defined as CUMSUMₙ = MAX(CUMSUMₙ₋₁, 0) + (HRₙ - MEAN(HR₁₋ₙ))

1. Calculating HRSlope Efficiently

Instead of looping, we can use rolling window sums to compute the necessary statistics for the slope formula. The slope of a linear regression between x (withinNightNo) and y (HR) can be calculated using:

slope = (n*sum(x*y) - sum(x)*sum(y)) / (n*sum(x²) - sum(x)²)

Where n is the number of observations in the window.

We'll use frollsum from data.table to compute rolling sums for each nightNo with a window size of 10 (aligned to the right):

# Calculate rolling sums for each nightNo, window=10, align=right
allData[, `:=`(
  sumX = frollsum(withinNightNo, n=10, align="right", na.rm=FALSE),
  sumY = frollsum(HR, n=10, align="right", na.rm=FALSE),
  sumXY = frollsum(withinNightNo*HR, n=10, align="right", na.rm=FALSE),
  sumX2 = frollsum(withinNightNo^2, n=10, align="right", na.rm=FALSE),
  n_win = frollsum(rep(1, .N), n=10, align="right", na.rm=FALSE)
), by = nightNo]

# Compute slope, set to NaN when n_win < 2 (can't compute slope with <2 points)
allData[, HRSlope := ifelse(n_win < 2, NaN, 
                            (n_win*sumXY - sumX*sumY) / (n_win*sumX2 - sumX^2))]

# Clean up temporary columns
allData[, c("sumX", "sumY", "sumXY", "sumX2", "n_win") := NULL]

2. Calculating HRCumsum Efficiently

The custom cumulative sum has two parts:

  • First, compute HRₙ - mean(HR₁₋ₙ) for each row within a nightNo
  • Then apply the recursive rule: CUMSUMₙ = max(CUMSUMₙ₋₁, 0) + current_part

We can compute this using grouped cumulative sums and a recursive calculation with Reduce (vectorized within each group):

# First compute the (HR - mean(1..n)) part for each nightNo
allData[, hr_part := HR - cumsum(HR)/seq_len(.N), by = nightNo]

# Apply the recursive max + sum rule using Reduce within each group
allData[, HRCumsum := Reduce(function(prev, curr) max(prev, 0) + curr, 
                             hr_part, 
                             accumulate = TRUE), 
        by = nightNo]

# Clean up temporary column
allData[, hr_part := NULL]

Full Code & Verification

Putting it all together, here's the complete script:

library(data.table)

# Sample data
allData <- data.table(nightNo=c(1,1,1,1,1,1,2,2,2,2), 
                      withinNightNo=c(1,2,3,4,5,6,1,2,3,4), 
                      HR=c(1:10))

# Calculate HRSlope
allData[, `:=`(
  sumX = frollsum(withinNightNo, n=10, align="right", na.rm=FALSE),
  sumY = frollsum(HR, n=10, align="right", na.rm=FALSE),
  sumXY = frollsum(withinNightNo*HR, n=10, align="right", na.rm=FALSE),
  sumX2 = frollsum(withinNightNo^2, n=10, align="right", na.rm=FALSE),
  n_win = frollsum(rep(1, .N), n=10, align="right", na.rm=FALSE)
), by = nightNo]

allData[, HRSlope := ifelse(n_win < 2, NaN, 
                            (n_win*sumXY - sumX*sumY) / (n_win*sumX2 - sumX^2))]

allData[, c("sumX", "sumY", "sumXY", "sumX2", "n_win") := NULL]

# Calculate HRCumsum
allData[, hr_part := HR - cumsum(HR)/seq_len(.N), by = nightNo]

allData[, HRCumsum := Reduce(function(prev, curr) max(prev, 0) + curr, 
                             hr_part, 
                             accumulate = TRUE), 
        by = nightNo]

allData[, hr_part := NULL]

# View the result
print(allData)

Running this will give you exactly the expected output:

nightNo withinNightNo HR HRSlope HRCumsum
1:       1             1  1     NaN      0.0
2:       1             2  2       1      0.5
3:       1             3  3       1      1.5
4:       1             4  4       1      3.0
5:       1             5  5       1      5.0
6:       1             6  6       1      7.5
7:       2             1  7     NaN      0.0
8:       2             2  8       1      0.5
9:       2             3  9       1      1.5
10:      2             4 10       1      3.0

Key Efficiency Notes

  • HRSlope: Uses frollsum which is implemented in C, so it's orders of magnitude faster than loops. The window size of 10 ensures we only look at the most recent 10 rows per night.
  • HRCumsum: Avoids double loops by first computing the mean part with vectorized cumulative sums, then using Reduce within each group (which is still vectorized and much faster than row-wise loops).

内容的提问来源于stack exchange,提问作者Henk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:45:21