【问题标题】:How to remove records from dataframe that fall outside variable-specific ranges? [R]如何从数据框中删除超出特定变量范围的记录? [R]
【发布时间】:2017-02-19 23:12:40
【问题描述】:

我有一个要应用于数据的数据框和预测模型。但是,我想过滤掉模型可能不太适用的记录。为此,我有另一个数据框,其中包含每个变量在训练数据中观察到的最小值和最大值。我想从我的新数据中删除那些有一个或多个值超出指定范围的记录。

为了让我的问题更清楚,我的数据可能如下所示:

  id   x       y     
 ---- ---- --------- 
   1    2     30521  
   2   -1      1835  
   3    5     25939  
   4    4   1000000  

这是我的第二张表,包含最小值和最大值:

  var   min    max   
 ----- ----- ------- 
  x       1       5  
  y       0   99999  

在本例中,我想在我的数据中标记以下记录:2(低于 x 的最小值)和 4(高于 y 的最大值)。

我怎样才能在 R 中轻松做到这一点?我有一种预感,有一些聪明的 dplyr 代码可以完成这项任务,但我不知道它会是什么样子。

【问题讨论】:

    标签: r outliers


    【解决方案1】:

    你的数据是这样的:

    df = data.frame(x=c(2,-1,5,4,7,8), y=c(30521, 1800, 25000,1000000, -5, 10))
    limits = data.frame("var"=c("x", "y"), min=c(1,0), max=c(5,99999))
    

    您可以将sweep 函数与运算符'>''<' 一起使用,这非常简单!

    sweep(df, 2, limits[, 2], FUN='>') & sweep(df, 2, limits[, 3], FUN='<')
    ####          x     y
    #### [1,]  TRUE  TRUE
    #### [2,] FALSE  TRUE
    #### [3,] FALSE FALSE
    #### [4,]  TRUE FALSE
    #### [5,] FALSE FALSE
    #### [6,] FALSE  TRUE
    

    正确的位置告诉您要为每个变量保留哪些观察结果。 它应该适用于任意数量的变量

    之后,如果您需要全局标志(至少在一列中有标志),您可以运行这个简单的行(res 是上一个输出)

    apply(res, 1, all)
    #### [1]  TRUE FALSE FALSE FALSE FALSE FALSE
    

    【讨论】:

      【解决方案2】:

      不是很优雅,但无论如何:

      df <- read.table(header=T, text="  id   x       y     
         1    2     30521  
         2   -1      1835  
         3    5     25939  
         4    4   1000000 ") 
      df
      ranges <- read.table(header=T, text="  var   min    max   
        x       1       5  
        y       0   99999")
      
      ranges <- ranges[match(ranges[,1], names(df)[-1]), ] # sort ranges, if necessary
      matrixStats::rowAnys(
        !sapply(seq_along(df)[-1], function(x) {
          df[,x]>=ranges[x-1,2] & df[,x]<=ranges[x-1,3]
        })
      ) -> df$flag
      df$flag
      # [1] FALSE  TRUE FALSE  TRUE
      

      【讨论】:

        【解决方案3】:

        类似 dplyr 的东西:

        library(dplyr)
        df <- read.table(text = "  id   x       y     
                   1    2     30521  
                   2   -1      1835  
                   3    5     25939  
                   4    4   1000000  ", header = TRUE)
        
        
        dfilte <- read.table(text = "  var   min    max
          x       1       5  
          y       0   99999  ", header = TRUE)
        
        
        df  %>% mutate(flag_x = x %in% dfilte[1, -1],
                       flax_y = y %in% dfilte[2, -1])
        

        产生这个输出:

          id  x       y flag_x flax_y
        1  1  2   30521  FALSE  FALSE
        2  2 -1    1835  FALSE  FALSE
        3  3  5   25939   TRUE  FALSE
        4  4  4 1000000  FALSE  FALSE
        

        【讨论】:

        • 这些标志是错误的,这个脚本只检查数据实际上是否等于最小值或最大值,对吧?还有一种方法可以将其扩展到更多的变量,而不必为每个变量添加新的代码行和标志列?
        • 我不清楚。您能否提供所需的输出? @A.Stam 谢谢你
        【解决方案4】:

        并不真正了解您想要的输出,但这适用于任何范围和任何数量的数据:

        > df
        
          id  x       y
        1  1  2   30521
        2  2 -1    1835
        3  3  5   25939
        4  4  4 1000000
        
        
        #I transpose your filter data frame so its easier to work with.
        > dfFilter
        
            x     y
        min 1     0
        max 5 99999
        

        然后您可以根据dfFilter 中的范围应用您的过滤器:

        #Flag original dataframe with values between the minimum x and maximum x 
        
           df$flag_x=ifelse(df$x > min(dfFilter$x) & df$x < max(dfFilter$x), "yes","no")
        
        
        #Flag original dataframe with values between the minimum y and maximum y
        
           df$flag_y=ifelse(df$y > min(dfFilter$y) & df$y < max(dfFilter$y), "yes","no")
        

        所以输出看起来像这样:

          id  x       y flag_x flag_y
        1  1  2   30521    yes    yes
        2  2 -1    1835     no    yes
        3  3  5   25939     no    yes
        4  4  4 1000000    yes    yes
        

        当然,您可以更改此过滤器或对其进行任何数学运算,以获得所需的输出(例如 x-2 的最小值:min(dfFilter$x)-2)。

        希望它有效。

        【讨论】:

          【解决方案5】:

          我认为您的问题非常适合在基础 R 中使用 cut 函数:

          df$to.remove <- is.na(cut(df$x, breaks = ranges[1,][,-1])) | 
                          is.na(cut(df$y, breaks = ranges[2,][,-1]))
          
          #  id  x       y to.remove
          #1  1  2   30521     FALSE
          #2  2 -1    1835      TRUE
          #3  3  5   25939     FALSE
          #4  4  4 1000000      TRUE
          

          is.na(...) 将为您提供一个逻辑向量,其中超出指定范围的值为TRUE。最后,您应用|,即or 运算符来决定哪些必须被删除。

          要清理您的数据,您只需要这样做:

          df <- df[!df$to.remove,]
          

          编辑

          我刚刚注意到(从您的评论中)您的数据框包含的变量不仅仅是xy。在这种情况下,您可以定义一个名为 f 的函数,并对数据框中的变量执行以下操作。

          f <- function(x, xrange, y, yrange) {
          (is.na(cut(x, breaks = xrange)) | is.na(cut(y, breaks = yrange)))}
          
          res <- f(df$x, ranges[1,][-1], df$y, ranges[2,][-1])
          

          数据

          df <- structure(list(id = 1:4, x = c(2L, -1L, 5L, 4L), y = c(30521L, 
          1835L, 25939L, 1000000L)), .Names = c("id", "x", "y"), class = "data.frame", row.names = c(NA, 
          -4L))
          
          ranges <- structure(list(var = structure(1:2, .Label = c("x", "y"), class = "factor"), 
              min = c(1L, 0L), max = c(5L, 99999L)), .Names = c("var", 
          "min", "max"), class = "data.frame", row.names = c(NA, -2L))
          

          【讨论】:

            猜你喜欢
            • 2021-08-02
            • 2012-01-03
            • 2022-12-11
            • 2014-10-09
            • 2013-10-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-04-07
            相关资源
            最近更新 更多