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

如何构建循环函数检测大规模时间序列数据框中的Outliers

多时间序列数据框的异常值检测可复用实现

需求概述

  • 处理结构统一的时间序列数据框:首列为分组名称(Name),其余列为不同时间节点的数值(允许0和NA,计算时需排除NA)
  • 对每行(每个分组)计算:均值、标准差,据此生成异常值阈值Tmin = mean - 3*sd和Tmax = mean + 3*sd
  • 筛选超出阈值的异常值,输出仅包含Name、outlier(对应时间列名)、values(异常值)的结果表格
  • 实现可复用函数,适配同结构的新数据框

原尝试代码

for (i in 1:nrow(x)) {
  mean <- mean(as.numeric(data.frame(x[i,2:50])))
  sd <-   sd(as.numeric(data.frame(x[i,2:50])))
  Tmin <- mean - (3*sd)
  Tmax <- mean + (3*sd)
  print(x[which(x < Tmin | x > Tmax)])
  i <- i+1
}

原代码存在的问题:

  • 硬编码列范围2:50,无法适配列数不同的同结构数据
  • 未处理NA(计算均值/标准差时需加na.rm=TRUE)
  • 未关联异常值对应的分组名称和时间列名,输出格式不符合需求
  • 手动自增i属于冗余操作(for循环会自动迭代)

优化后的可复用实现

1. Base R版本(无需额外依赖)

detect_outliers <- function(df) {
  result_list <- list()
  
  for (i in seq_len(nrow(df))) {
    # 获取当前分组名称
    current_name <- df[i, 1]
    # 提取数值列并转为数值型
    current_values <- as.numeric(df[i, -1])
    # 过滤NA值
    valid_values <- current_values[!is.na(current_values)]
    
    # 跳过无法计算标准差的情况(非NA值少于2个)
    if (length(valid_values) < 2) next
    
    # 计算阈值
    mean_val <- mean(valid_values, na.rm = TRUE)
    sd_val <- sd(valid_values, na.rm = TRUE)
    Tmin <- mean_val - 3 * sd_val
    Tmax <- mean_val + 3 * sd_val
    
    # 定位异常值及其对应列名
    outlier_pos <- which(current_values < Tmin | current_values > Tmax)
    if (length(outlier_pos) > 0) {
      outlier_cols <- colnames(df)[-1][outlier_pos]
      outlier_vals <- current_values[outlier_pos]
      
      # 整理结果行
      result_list[[i]] <- data.frame(
        Name = rep(current_name, length(outlier_pos)),
        outlier = outlier_cols,
        values = outlier_vals,
        stringsAsFactors = FALSE
      )
    }
  }
  
  # 合并所有结果并返回
  do.call(rbind, result_list)
}

2. Tidyverse版本(简洁易读)

如果熟悉dplyr和tidyr,可以用长格式数据处理,代码更简洁:

library(dplyr)
library(tidyr)

detect_outliers_tidy <- function(df) {
  df %>%
    # 宽表转长表,统一处理数值列
    pivot_longer(cols = -Name, names_to = "outlier", values_to = "values") %>%
    group_by(Name) %>%
    # 过滤NA值
    filter(!is.na(values)) %>%
    # 计算均值、标准差和阈值
    mutate(
      mean_val = mean(values, na.rm = TRUE),
      sd_val = sd(values, na.rm = TRUE),
      Tmin = mean_val - 3 * sd_val,
      Tmax = mean_val + 3 * sd_val
    ) %>%
    # 筛选异常值
    filter(values < Tmin | values > Tmax) %>%
    ungroup() %>%
    # 保留目标列
    select(Name, outlier, values) %>%
    arrange(Name)
}

使用示例

# 构造样本测试数据
sample_df <- data.frame(
  Name = c("Banking sect.", "Money laund. sect.", "Households"),
  "2015Q1" = c(63.4442, 0, NA),
  "2015Q2" = c(61.73465, 0, NA),
  "2015Q3" = c(67.33452, 0, 1.2),
  "2015Q4" = c(52.34546, 2.4, NA),
  "2016Q1" = c(12.3334, 0, 9.6),
  stringsAsFactors = FALSE
)

# 调用函数
result_base <- detect_outliers(sample_df)
result_tidy <- detect_outliers_tidy(sample_df)

print(result_base)

输出示例:

Name outlier   values
1 Banking sect. 2016Q1 12.33340

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 18:50:26