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

如何用R语言IQR方法仅对连续变量移除异常值并更新数据框

使用R语言IQR方法仅对连续变量移除异常值

我手头有一个包含53列的数据集,其中17列为连续变量,其余是分类变量。需要用R语言的IQR方法仅对连续变量移除异常值并更新数据框。找到的在线函数未考虑分类列的情况,原代码如下:

sample_data <- data.frame(x=c(1, 2, 3, 4, 3, 2, 3, 4, 4, 5, 0),
                           y=c(4, 3, 5, 7, 8, 5, 9, 7, 6, 5, 0),
                           z=c(1, 3, 2, 9, 8, 7, 0, 8, 7, 2, 3))
print("Display original dataframe")
print(sample_data)

detect_outlier <- function(x) {
  
  # calculate first quantile
  Quantile1 <- quantile(x, probs=.25)
  
  # calculate third quantile
  Quantile3 <- quantile(x, probs=.75)
  
  # calculate inter quartile range
  IQR = Quantile3-Quantile1
  
  # return true or false
  x > Quantile3 + (IQR*1.5) | x < Quantile1 - (IQR*1.5)
}

# create remove outlier function
remove_outlier <- function(dataframe,
                           columns=names(dataframe)) {
  
  # for loop to traverse in columns vector
  for (col in columns) {
    
    # remove observation if it satisfies outlier function
    dataframe <- dataframe[!detect_outlier(dataframe[[col]]), ]
  }
  
  # return dataframe
  print("Remove outliers")
  print(dataframe)
}

remove_outlier(sample_data, c('x', 'y', 'z', 'w'))

以下是数据集的所有变量:

'car.deliver.airport.num','car.deliver.hotel.num','car.deliver.train.station.num','car.displayed.turo.review.num',  'car.displayed.turo.review.num.past.12m','car.displayed.turo.review.num.past.18m','car.displayed.turo.review.num.past.6m','car.displayed.user.review.num','car.displayed.user.review.num.past.12m','car.displayed.user.review.num.past.18m','car.displayed.user.review.num.past.6m','car.extra.mile.fee','car.extra.num','car.extra.phone.mount','car.extra.portable.gps','car.extra.post.trip.cleaning','car.extra.prepaid.ev.recharge','car.extra.prepaid.refuel','car.extra.stroller','car.extra.unlimited.mileage','car.faq.num','car.instant.book','car.insurance','car.miles.included','car.photo.num','car.trip.price','host.car.num'

原代码存在两个问题:一是会遍历传入的所有列(包括分类列),但分类变量不适合用IQR判断异常;二是循环逐列删除的方式会导致后续列的异常判断基于已删减的数据,逻辑不合理。


解决方案

步骤1:定义连续变量列表

先从变量中筛选出17个连续变量,整理成向量:

continuous_vars <- c(
  'car.deliver.airport.num', 'car.deliver.hotel.num', 
  'car.deliver.train.station.num', 'car.displayed.turo.review.num',
  'car.displayed.turo.review.num.past.12m', 'car.displayed.turo.review.num.past.18m',
  'car.displayed.turo.review.num.past.6m', 'car.displayed.user.review.num',
  'car.displayed.user.review.num.past.12m', 'car.displayed.user.review.num.past.18m',
  'car.displayed.user.review.num.past.6m', 'car.extra.mile.fee', 'car.extra.num',
  'car.faq.num', 'car.miles.included', 'car.photo.num', 'car.trip.price', 'host.car.num'
)

(可根据实际情况调整,确保仅包含数值型连续变量)

步骤2:优化异常值检测与移除函数

修改原函数,仅处理连续变量,且先计算所有连续变量的非异常行索引,再统一过滤数据框:

# 异常值检测函数:仅处理数值型变量,兼容缺失值
detect_outlier <- function(x) {
  if (!is.numeric(x)) {
    warning("输入变量不是数值型,跳过异常值检测")
    return(rep(FALSE, length(x)))
  }
  q1 <- quantile(x, probs = 0.25, na.rm = TRUE)
  q3 <- quantile(x, probs = 0.75, na.rm = TRUE)
  iqr_val <- q3 - q1
  x > q3 + 1.5 * iqr_val | x < q1 - 1.5 * iqr_val
}

# 移除异常值函数:仅处理指定连续变量
remove_outlier_continuous <- function(dataframe, continuous_cols) {
  # 验证连续变量是否存在于数据框中
  valid_cols <- intersect(continuous_cols, names(dataframe))
  if (length(valid_cols) == 0) {
    stop("没有有效的连续变量列")
  }
  
  # 标记所有连续变量均无异常的行
  non_outlier_rows <- apply(dataframe[valid_cols], 1, function(row) {
    !any(detect_outlier(row), na.rm = TRUE)
  })
  
  # 返回过滤后的数据框,保留所有列
  filtered_df <- dataframe[non_outlier_rows, , drop = FALSE]
  cat("移除异常值后的数据框行数:", nrow(filtered_df), "\n")
  return(filtered_df)
}

步骤3:处理数据集

假设你的数据集名为df,运行以下代码:

# 加载数据集(示例)
# df <- read.csv("your_data.csv")

# 移除连续变量的异常值
cleaned_df <- remove_outlier_continuous(df, continuous_vars)

函数说明

  • detect_outlier:增加非数值型变量判断避免报错,加入na.rm = TRUE处理缺失值
  • remove_outlier_continuous:
    • 先验证输入的连续变量有效性
    • 逐行检查:只要某行在任意一个连续变量中是异常值,就标记为移除对象
    • 保留所有分类变量和处理后的连续变量

示例测试

用你提供的sample_data测试,假设x、y是连续变量,z是分类变量:

sample_data <- data.frame(
  x=c(1, 2, 3, 4, 3, 2, 3, 4, 4, 5, 0),
  y=c(4, 3, 5, 7, 8, 5, 9, 7, 6, 5, 0),
  z=c(1, 3, 2, 9, 8, 7, 0, 8, 7, 2, 3)
)

test_continuous <- c("x", "y")
cleaned_sample <- remove_outlier_continuous(sample_data, test_continuous)
print(cleaned_sample)

输出会移除第11行(x=0、y=0为异常值),同时保留分类列z。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 06:05:24