计算一组特定列的异常值,然后识别具有 >5 列异常值的 ID

Calculate outliers of a group of specific columns then identify ids which have >5 columns with outliers

我正在使用大数据框 (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。

这有意义吗?我不确定这个问题是否也推荐使用循环。

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

您可以创建一个函数,其中 returns 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)

我假设你的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 

除了已经提供的巧妙答案之外,另一种方法是将相关列转换为矩阵并使用一些快速矩阵运算:

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)