R语言如何批量移除数据框所有列异常值(保留含NA行)
基于IQR替换异常值(保留含NA的行)
问题描述
我有一个包含431个变量、140条观测值的数据框,需要移除异常值,但数据集存在多个NA值,不想删除所有含NA的行。尝试用IQR方法移除异常值,已获取四分位数和IQR、上下限,但替换异常值的代码未生效,在iris数据集测试也失败,求无需手动选择所有列名即可过滤异常值的方法。
原测试代码(iris数据集):
data(iris, package = "datasets") completeData <- iris[-5] apply(completeData,2,quantile, probs=c(0.25,0.75), na.rm=TRUE) -> Quartiles sapply(completeData,IQR, na.rm=TRUE) -> iqr Lower <- Quartiles[1,]-1.5*iqr Upper <- Quartiles[2,]+1.5*iqr data_no_outlier <- replace(completeData, completeData < Lower & completeData > Upper, NA)
错误原因
- 逻辑运算符错误:
completeData < Lower & completeData > Upper表示同时满足「小于下限」且「大于上限」,这在逻辑上不可能成立,应该用|(或运算符)表示「小于下限或大于上限」。 - 维度匹配问题:直接用整个数据框与列向量Lower/Upper比较时,R的广播规则会导致维度不匹配,需要按列逐元素进行判断。
解决方案
以下三种方法均无需手动指定列名,可批量处理所有数值列:
方法1:基础R的apply函数
# 定义批量替换异常值的函数 replace_outliers <- function(x) { # 计算四分位数与IQR qs <- quantile(x, probs = c(0.25, 0.75), na.rm = TRUE) iqr_val <- IQR(x, na.rm = TRUE) # 计算上下限 lower <- qs[1] - 1.5 * iqr_val upper <- qs[2] + 1.5 * iqr_val # 替换异常值为NA x[x < lower | x > upper] <- NA return(x) } # 处理自定义数据集 data <- df2[,4:434] data_no_outlier <- as.data.frame(apply(data, 2, replace_outliers)) # 测试iris数据集 data(iris) completeData <- iris[-5] completeData_no_outlier <- as.data.frame(apply(completeData, 2, replace_outliers))
方法2:tidyverse(dplyr)风格
适合熟悉tidyverse生态的用户,用across批量处理所有列:
library(dplyr) # 处理自定义数据集 data_no_outlier <- df2[,4:434] %>% mutate(across(everything(), ~{ qs <- quantile(.x, probs = c(0.25, 0.75), na.rm = TRUE) iqr_val <- IQR(.x, na.rm = TRUE) lower <- qs[1] - 1.5 * iqr_val upper <- qs[2] + 1.5 * iqr_val .x[.x < lower | .x > upper] <- NA .x })) # 测试iris数据集 completeData_no_outlier <- iris %>% select(-Species) %>% mutate(across(everything(), ~{ qs <- quantile(.x, probs = c(0.25, 0.75), na.rm = TRUE) iqr_val <- IQR(.x, na.rm = TRUE) lower <- qs[1] - 1.5 * iqr_val upper <- qs[2] + 1.5 * iqr_val .x[.x < lower | .x > upper] <- NA .x }))
方法3:data.table(高效处理大数据)
如果数据集规模较大,data.table的处理效率更优:
library(data.table) # 处理自定义数据集 data_dt <- as.data.table(df2[,4:434]) for (col in names(data_dt)) { qs <- quantile(data_dt[[col]], probs = c(0.25, 0.75), na.rm = TRUE) iqr_val <- IQR(data_dt[[col]], na.rm = TRUE) lower <- qs[1] - 1.5 * iqr_val upper <- qs[2] + 1.5 * iqr_val data_dt[get(col) < lower | get(col) > upper, (col) := NA] } data_no_outlier <- as.data.frame(data_dt) # 测试iris数据集 iris_dt <- as.data.table(iris)[, -"Species"] for (col in names(iris_dt)) { qs <- quantile(iris_dt[[col]], probs = c(0.25, 0.75), na.rm = TRUE) iqr_val <- IQR(iris_dt[[col]], na.rm = TRUE) lower <- qs[1] - 1.5 * iqr_val upper <- qs[2] + 1.5 * iqr_val iris_dt[get(col) < lower | get(col) > upper, (col) := NA] } completeData_no_outlier <- as.data.frame(iris_dt)
内容的提问来源于stack exchange,提问作者Nat23
相关产品推荐
相关产品推荐

