首页 > 解决方案 > 从列表中的数据框的多个列中删除异常值

问题描述

我有一个数据框列表,每个数据框都有多个列,其中包含我想删除并替换为 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

标签: rdataframe

解决方案


我认为@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 列。我从函数中排除了该列。


推荐阅读