【问题标题】:How to replace outliers with NA having a particular range of values in R?如何用 R 中具有特定值范围的 NA 替换异常值?
【发布时间】:2016-10-24 03:50:05
【问题描述】:

我有气候数据,我正在尝试用NA 替换异常值。 我没有使用 boxplot(x)$out 是因为我有一个值范围来考虑计算异常值。

temp_range <- c(-15, 45)
wind_range <- c(0, 15)
humidity_range <- c(0, 100)

我的数据框是这样的

df with outliers

(我根据范围突出显示了应该用 NA 替换的值。)

所以temp1temp2异常值必须根据temp_range替换为NAwind的异常值应根据wind_range替换为NA,最后humidity的异常值必须根据humidity_range替换为NA

这是我得到的:

df <- read.csv2("http://pastebin.com/raw/vwqBu2M5", stringsAsFactors = FALSE)

df[,2:5] = apply(df[,2:5], 2, function(x) as.numeric(x))

#Ranges
temp_range <- c(-15, 45)
wind_range <- c(0, 15)
humidity_range <- c(0, 100)

#Function to detect outlier
in_interval <- function(x, interval){
  stopifnot(length(interval) == 2L)
  interval[1] <= x & x <= interval[2]
}


#Replace outliers according to temp_range
cols <- c('temp1', 'temp2')
df[, cols] <- lapply(df[, cols], function(x) {

  x[in_interval(x, temp_range)==FALSE] <- NA
  x
})

我正在为每个范围做最后一部分代码(替换)。有没有办法简化它,这样我就可以避免很多重复?

最后一件事,假设 cols &lt;- c('wind') 这会向我发出警告,并将整个 wind 列替换为常量。

Warning message:
In `[<-.data.frame`(`*tmp*`, , cols, value = list(23.88, 23.93,  :
  provided 10 variables to replace 1 variables

有什么建议吗?

【问题讨论】:

    标签: r replace range lapply outliers


    【解决方案1】:

    要更动态地执行此操作,请使用字典:与每个变量相关联的异常值的数据框。

    这里我在 R 中创建它,但将它放在 csv 中会更实用,这样您就可以轻松编辑它。

    df <- read.csv2("http://pastebin.com/raw/vwqBu2M5", stringsAsFactors = FALSE)
    
    df[,2:5] = apply(df[,2:5], 2, function(x) as.numeric(x))
    
    
    df_dict <- data.frame(variable = c("temp1", "temp2", "wind", "humidity"), 
                           out_low = c(-15, -15, 0, 0), 
                           out_high =c(45, 45, 15, 100))
    
    for (var in df_dict$variable) {
    
      df[[var]][df[[var]] < df_dict[df_dict$variable == var, ]$out_low | df[[var]] > df_dict[df_dict$variable == var, ]$out_high] <- NA
    
    }
    

    【讨论】:

      【解决方案2】:

      我认为你让它变得比它需要的更复杂。您可以使用逻辑向量选择性地仅替换变量中的某些值:

      df <- read.csv2("http://pastebin.com/raw/vwqBu2M5", stringsAsFactors = FALSE)
      
      df[,2:5] = apply(df[,2:5], 2, function(x) as.numeric(x))
      
      #Ranges
      temp_range <- c(-15, 45)
      wind_range <- c(0, 15)
      humidity_range <- c(0, 100)
      
      df$temp1[df$temp1 < temp_range[1] | df$temp1 > temp_range[2]] <- NA
      df$temp2[df$temp2 < temp_range[1] | df$temp2 > temp_range[2]] <- NA
      df$wind[df$wind < wind_range[1] | df$wind > wind_range[2]] <- NA
      df$humidity[df$humidity < humidity_range[1] | df$humidity > humidity_range[2]] <- NA
      

      基本上,您所做的只是获取一个变量,创建一个仅选择范围之外的值的逻辑向量,然后将这些值替换为 NA

      这将为您提供以下信息(与您的图像不太匹配,但根据您的范围,数字似乎是正确的):

                        time temp2 wind humidity temp1
      1  2006-11-22 22:00:00    NA 0.00    56.95 23.88
      2  2006-11-22 23:00:00  15.5 0.00    58.21 23.93
      3  2006-11-23 00:00:00    NA   NA    62.95 23.81
      4  2006-11-23 01:00:00  12.0 0.30    70.15    NA
      5  2006-11-23 02:00:00  35.0 0.07    76.46 21.63
      6  2006-11-23 03:00:00  12.0 0.79       NA 21.81
      7  2006-11-23 04:00:00  35.0 0.50    69.11 21.04
      8  2006-11-23 05:00:00  14.0 0.37    71.86 20.32
      9  2006-11-23 06:00:00  -9.0 0.26    70.97 20.50
      10 2006-11-23 07:00:00    NA 0.03    78.02    NA
      

      【讨论】:

      • 我更新了图片,结果应该和你的输出一样。是否可以在 lapply 中执行第一条和第二条替换线?它们看起来非常相似,我只发布了一个示例,我有更多基于temp_range 的列,所以这个替换行数量会增加,我希望更动态地进行。
      【解决方案3】:

      你可以定义一个函数,

      check_inRange <- function(col, range) {
         df[col] >= range[1] & df[col] <= range[2]
      }
      

      然后对于每一列,您可以将此函数称为

      df[!check_inRange("temp1", temp_range), "temp1"] <- NA
      df[!check_inRange("temp2", temp_range), "temp2"] <- NA
      df[!check_inRange("wind", wind_range), "wind"] <- NA
      df[!check_inRange("humidity", humidity_range), "humidity"] <- NA
      

      这将替换各个列中超出NA范围的所有值

      【讨论】:

      • check_inRange 函数中,条件必须为df[col] &gt;= range[1] &amp; df[col] &lt;= range[2],因此不会替换0,因为它不是wind 列中的异常值(见附图)
      • @Martin 好的..更新了答案。同样在temp2 的图像中,第 35 列不应突出显示。因为它在范围内。 (-15, 45) 不是吗?
      • 你是对的。更新。顺便说一句,很好的解决方案。该功能就像一个魅力,但如果我有另一个数据框看起来有点硬编码。我会继续努力,因为我可以使用相同的函数首先绘制异常值并调整颜色,然后用 NA 替换它们。
      • 好吧,如果你有不同的数据帧,你也可以将数据帧传递给函数参数。类似check_inRange &lt;- function(col, range, df)
      猜你喜欢
      • 2017-12-19
      • 2021-10-24
      • 1970-01-01
      • 1970-01-01
      • 2021-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多