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

如何加速大时间序列数据集的Whittaker-Henderson平滑计算?

解决盆栽重量时间序列平滑的效率与精度问题

一、加速Whittaker-Henderson算法并兼容dplyr::group_by()

pracma包里的whittaker()速度慢主要是因为实现不够高效,比如用了非最优的矩阵运算。可以用Rcpp结合Armadillo重写一个快速版本,完全兼容分组处理:

步骤1:编写Rcpp加速函数

创建fast_whittaker.cpp文件,内容如下:

#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]

// [[Rcpp::export]]
arma::vec fast_whittaker(const arma::vec& y, double lambda, int d = 2) {
  int n = y.n_elem;
  arma::mat D = arma::diff(arma::eye(n, n), d);
  arma::mat A = arma::eye(n, n) + lambda * D.t() * D;
  arma::vec z = arma::solve(A, y);
  return z;
}

步骤2:在R中调用并结合dplyr

library(dplyr)
library(Rcpp)

# 编译加速函数
sourceCpp("fast_whittaker.cpp")

# 分组处理你的数据集(假设数据集为pot_data,含pot_id、datetime、weight列)
smoothed_data <- pot_data %>%
  group_by(pot_id) %>%
  mutate(smoothed_weight = fast_whittaker(weight, lambda = 1e5)) %>% # lambda按需调整
  ungroup()

这个版本依赖Armadillo的高效线性代数库,速度比pracma原版快一个数量级以上,完全适配分组场景。

二、高效抗突刺的替代平滑算法

如果不想折腾Whittaker,试试这些兼顾速度和抗干扰的方案:

1. 滑动中位数+滑动平均组合

先去突刺再平滑,速度极快,适合高频时间序列:

library(dplyr)
library(zoo)

smoothed_data <- pot_data %>%
  group_by(pot_id) %>%
  # 滑动中位数去突刺(窗口20个点=1小时,按需调整)
  mutate(weight_med = rollmedian(weight, k = 20, fill = "extend")) %>%
  # 滑动平均平滑(窗口60个点=3小时,按需调整)
  mutate(smoothed_weight = rollmean(weight_med, k = 60, fill = "extend")) %>%
  ungroup()

2. LOESS局部回归

比Savitzky-Golay抗突刺,拟合灵活,速度适中:

library(dplyr)

smoothed_data <- pot_data %>%
  group_by(pot_id) %>%
  # span控制平滑程度,值越小越贴近原始数据
  mutate(smoothed_weight = predict(loess(weight ~ as.numeric(datetime), span = 0.1))) %>%
  ungroup()

3. 稳健样条回归

用mgcv的广义加性模型,抗异常值能力强,拟合效果接近Whittaker:

library(dplyr)
library(mgcv)

smoothed_data <- pot_data %>%
  group_by(pot_id) %>%
  # gamma越大对突刺越不敏感,bs="cr"是立方样条
  mutate(smoothed_weight = predict(gam(weight ~ s(as.numeric(datetime), bs = "cr"), 
                                       gamma = 1.4, method = "REML"))) %>%
  ungroup()

三、修复pracma::whittaker()的性能问题

如果坚持要用pracma的版本,简化其内部计算逻辑:

fast_pracma_whittaker <- function(y, lambda, d = 2) {
  n <- length(y)
  # 直接计算差分矩阵,去掉pracma里的冗余检查
  D <- diff(diag(n), differences = d)
  A <- diag(n) + lambda * t(D) %*% D
  # 用基础R的solve,比pracma内部的求解更高效
  z <- solve(A, y)
  return(z)
}

然后在group_by里调用这个函数,比原版快不少,适合小批量数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 20:15:18