【问题标题】:Removing outliers from multiple columns for dataframes in a list从列表中的数据框的多个列中删除异常值
【发布时间】:2020-07-30 19:43:16
【问题描述】:

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

【问题讨论】:

  • 当然该函数不起作用,因为计算平均值和标准差时会考虑极端值等情况。因此,价值将保持不变。您可以尝试删除大于 IQR(x)quantile(x,0.75) 的值,如果您想要这样的方法,请告诉我!
  • 您还会收到警告,因为您正试图从 data_time 列中删除异常值。假设所有列都是数字,该函数被清楚地编写。当我在您的代码上运行您的数据时,我收到了 12 条警告!您的示例数据中只有 17 行,但 pnorm(-3) * 2 = .0027 因此,如果数据是正态分布的,那么在 1000 次观察中您只会期望 2.7 个异常值。

标签: r dataframe


【解决方案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 列。我从函数中排除了该列。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-12-22
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 2020-07-26
    • 2019-09-23
    • 1970-01-01
    • 2020-09-16
    相关资源
    最近更新 更多