【问题标题】:Calculate outliers of a group of specific columns then identify ids which have >5 columns with outliers计算一组特定列的异常值,然后识别具有 >5 列的异常值的 id
【发布时间】:2020-07-11 11:31:28
【问题描述】:

我正在使用大数据框 (df)。我想根据平均值 + 3 sd 计算特定列子集的异常值。

我首先提取了我想要的列,所以所有列的列名中都有颜色。

colors = colnames(df)[grep('color', colnames(df))]

我不确定我应该如何循环它以使用这个新变量计算所有列的异常值。我的公式是:

# id those with upper outliers
uthr = mean(df$color)+3*sd(df$color)
rm_u_ids = df$id[which(df$color >= uthr)]

# id those with lower outliers
lthr = mean(df$color)-3*sd(df$color)
rm_l_ids = df$id[which(df$color <= lthr)]

# remove those with both upper and lower outliers
rm_ids = sort(c(rm_u_ids, rm_l_ids))
df_2 = df %>% filter(!id %in% rm_ids)

现在,实际问题。 我想使用类似的东西来执行以下操作: 1) 对于colors 中的每种颜色,用异常值识别那些id,也许将此信息保存在其他地方, 2) 使用该信息(可能在列表或单独的数据框中),识别出现在 5 列或更多列中的 id,或 colors, 3) 使用此列表对原始数据框进行子集化,以便我们消除那些在 5 个颜色列或更多颜色列中具有异常值的 id。

这有意义吗?我不确定是否也建议针对此问题使用循环。

谢谢,如果我让它听起来比应该的更复杂,我很抱歉!

【问题讨论】:

    标签: r loops for-loop subset outliers


    【解决方案1】:

    您可以创建一个函数来返回 id 的异常值

    find_outlier <- function(df, x) {
      uthr = mean(x)+3*sd(x)
      rm_u_ids = df$id[which(x >= uthr)]
      # id those with lower outliers
      lthr = mean(x)-3*sd(x)
      rm_l_ids = df$id[which(x <= lthr)]
      # remove those with both upper and lower outliers
      unique(sort(c(rm_u_ids, rm_l_ids)))
    }
    

    将其应用于每个colors 列,用table 计算它们的计数并删除出现5 次以上的id

    all_ids <- lapply(df[colors], find_outlier, df = df)
    
    temp_tab <- table(unlist(all_ids))
    remove_ids <- names(temp_tab[temp_tab >= 5])
    subset(df, !id %in% remove_ids)
    

    【讨论】:

    • 嗨@Ronak Shah,感谢您的解决方案。我尝试使用它,但它在“lapply”功能处中断,因为“颜色”是字符。有没有办法解决这个问题?
    • @Erika 哎呀......对不起,它应该是 df[colors] in lapply。我已经更新了答案。你现在可以检查吗?
    【解决方案2】:

    我将假设您的 data.frame 只有您想要的数字变量

    findOutlierCols = function(color.df){
      hasOutliers = function(col){
        bds = mean(col) + c(-3,3)*sd(col)
        if(any(col <= bds[1]) || any(col >= bds[2])){
          return(TRUE)
        }else{
          return(FALSE)
        }
      }  
      apply(color.df, 2, hasOutliers)
    }
    
    ## make some fake data
    set.seed(123)
    x = matrix(rnorm(1000), ncol = 10)
    color.df = data.frame(x)
    colnames(x) = paste0("color.", colors()[1:10])
    color.df = apply(color.df, 2, function(col){col+rbinom(100, 5, 0.1)})
    
    boxplot(color.df)
    findOutlierCols(color.df)
    
    

    > findOutlierCols(color.df)
       X1    X2    X3    X4    X5    X6    X7    X8    X9   X10 
     TRUE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE FALSE FALSE 
    

    【讨论】:

      【解决方案3】:

      已经提供的聪明答案的替代方法是将相关列转换为矩阵并使用一些快速矩阵运算:

      df = iris
      colors = colnames(iris)[1:4]
      m = as.matrix(df[,colors])
      
      # Standardize the numeric values in each column
      m = scale(m)
      
      # Apply some outlier definition rules, e.g.
      # detect measurements with |Zscore|>3
      outliers = abs(m)>3
      # detect rows with at least 5 such measurements
      outliers = rowSums(outliers)
      which(outliers>=5)
      

      【讨论】:

        猜你喜欢
        • 2021-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多