从多个列中删除列表中数据框的异常值

时间:2020-07-30 19:43:16

标签: r dataframe

我有一个数据框列表,每个数据框都有多个列,其中包含我想删除并替换为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,但是我的实际数据具有一定范围的离群值。以下是我发现的here函数,我试图将其用于此目的。

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

1 个答案:

答案 0 :(得分:1)

我认为@Duck的评论在这里非常有用。使用整个数据集计算均值和标准差时,您将计算的离群值包括在内。这不会删除示例中的三个异常值。在计算均值和标准差之前,应先以某种方式限制数据,然后根据这些计算,可以消除异常值。也就是说,您应该从范围的高端/低端删除一些案例。问题是,在计算均值和标准差之前,您将排除多少个案例(或占案例的比例)?在这里,您可以使用 quantile 函数。这是我修改您的函数的方式:

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