r - 从列表中的数据框的多个列中删除异常值
问题描述
我有一个数据框列表,每个数据框都有多个列,其中包含我想删除并替换为 NA 的异常值。我的数据集非常大(每个数据框有 11 列,约 15,000 行),所以我尽力在下面创建一个可重现的示例:
df1 <- data.frame(date_time = c("2019-01-01", "2019-01-02", "2019-01-03", "2019-01-04", "2019-01-05", "2019-01-06", "2019-01-07", "2019-01-08", "2019-01-09", "2019-01-10", "2019-01-11", "2019-01-12", "2019-01-13", "2019-01-14", "2019-01-15","2019-01-16","2019-01-17"),
XH_warmed_air_1m = c(25, 23, 26, 30, 10, 15, 12, 0, 1, 5, -15, -12, -6, -1, 537, 435, 300),
XH_ambient_air_1m = c(25, 23, 26, 30, 10, 15, 12, 0, 1, 5, -15, -12, -6, -1, 537, 435, 300))
df2 <- data.frame(date_time = c("2019-01-01", "2019-01-02", "2019-01-03", "2019-01-04", "2019-01-05", "2019-01-06", "2019-01-07", "2019-01-08", "2019-01-09", "2019-01-10", "2019-01-11", "2019-01-12", "2019-01-13", "2019-01-14", "2019-01-15","2019-01-16","2019-01-17"),
XH_warmed_air_1m = c(25, 23, 26, 30, 10, 15, 12, 0, 1, 5, -15, -12, -6, -1, 537, 435, 300),
XH_ambient_air_1m = c(25, 23, 26, 30, 10, 15, 12, 0, 1, 5, -15, -12, -6, -1, 537, 435, 300))
df3 <- data.frame(date_time = c("2019-01-01", "2019-01-02", "2019-01-03", "2019-01-04", "2019-01-05", "2019-01-06", "2019-01-07", "2019-01-08", "2019-01-09", "2019-01-10", "2019-01-11", "2019-01-12", "2019-01-13", "2019-01-14", "2019-01-15","2019-01-16","2019-01-17"),
XH_warmed_air_1m = c(25, 23, 26, 30, 10, 15, 12, 0, 1, 5, -15, -12, -6, -1, 537, 435, 300),
XH_ambient_air_1m = c(25, 23, 26, 30, 10, 15, 12, 0, 1, 5, -15, -12, -6, -1, 537, 435, 300))
list_df <- list(df1=df1, df2=df2, df3=df3)
我想创建一个函数,用 NA 替换距离平均值 3 sd 的每一列的异常值。在给定的示例中,异常值是 537、435 和 300,但我的实际数据有一系列异常值。下面是我在这里找到的一个函数,我试图用于此目的。
remove_outliers <- function(df){
columns <- colnames(df)
for (i in columns){
Min <- mean(df[[i]]) - (3*sd(df[[i]]))
Max <- mean(df[[i]]) + (3*sd(df[[i]]))
df[[i]][df[[i]] < Min | df[[i]] > Max] <- NA
}
return(df)
}
list_df <- lapply(list_df, remove_outliers)
当我尝试将该函数应用于列表时,它似乎没有做任何事情。如何修复此函数,以便删除列表中每个数据框中的所有列(date_time 列除外)的异常值?
使用 R 版本 3.5.1,Mac OS X 10.13.6
解决方案
我认为@Duck 的评论在这里非常有用。当您使用整个数据集计算平均值和标准差时,您将计算中的异常值包括在内。这不会删除您示例中的三个异常值。在计算平均值和标准差之前,您应该以某种方式限制您的数据,然后根据这些计算,您可以删除异常值。也就是说,您应该从范围的高端/低端删除一些案例。问题是,在计算平均值和标准差之前,您将排除多少(或多少比例)案例?在那里,您可以使用分位数功能。这是我修改您的功能的方式:
remove_outliers = function(df) {
for (i in 2:ncol(df)) {
dat = df[which(df[,i] > quantile(df[,i], .1) & df[,i] < quantile(df[,i], .9)),i]
mean = mean(dat)
sd = sd(dat)
df[which( abs((df[,i]) - mean) > (sd * 3)), i] = NA
}
return(df)
}
这是将该函数应用于 df1 时的结果:
> remove_outliers(df1)
date_time XH_warmed_air_1m XH_ambient_air_1m
1 2019-01-01 25 25
2 2019-01-02 23 23
3 2019-01-03 26 26
4 2019-01-04 30 30
5 2019-01-05 10 10
6 2019-01-06 15 15
7 2019-01-07 12 12
8 2019-01-08 0 0
9 2019-01-09 1 1
10 2019-01-10 5 5
11 2019-01-11 -15 -15
12 2019-01-12 -12 -12
13 2019-01-13 -6 -6
14 2019-01-14 -1 -1
15 2019-01-15 NA NA
16 2019-01-16 NA NA
17 2019-01-17 NA NA
此外,正如@dcarlson 所说,您正在将该函数应用于 date_time 列。我从函数中排除了该列。
推荐阅读
- c# - 更改对象数组中的一个元素会更改所有元素,c#,如何按值分配对象
- chart.js - 如何在数据标签中给出断线
- vba - 存在命令按钮时的奇怪行为。字VBA
- python - 从范围创建十六进制代码列表
- java - Spring Boot,组合类的 Thymeleaf 验证
- c++ - 有没有办法修复编译器找不到特定的 openCV 变量/函数?
- javascript - 图像加载为空
- google-cloud-firestore - 如何创建具有类似于 JS ES6 中模板文字的变量的字符串?
- ajax - Yii2 Kartik 可编辑输入值只会在刷新后改变
- javascript - 如何设置倒数计时器在 00:00:00 或 =0 自动单击按钮时停止