Javascript:从数组中删除离群值?

Javascript:从数组中删除离群值?,javascript,statistics,Javascript,Statistics,如何删除异常值,如0、57218、60720和22684 是否有一个库可以做到这一点?这一切都取决于您对“异常值”的解释。一个共同的做法是: 高异常值是指超出第三个四分位数+1.5*的任何值 四分位间距(IQR) 低异常值是低于第一个四分位数-1.5*IQR的任何值 这也是所描述的方法 这很容易用一个函数来概括:)我试着把下面的内容写清楚;明显的重构机会确实存在请注意,使用此常用方法,给定的样本不包含任何外围值 values = [8160,8160,6160,22684,0,0,60720

如何删除异常值,如0、57218、60720和22684


是否有一个库可以做到这一点?

这一切都取决于您对“异常值”的解释。一个共同的做法是:

  • 高异常值是指超出第三个四分位数+1.5*的任何值 四分位间距(IQR)
  • 低异常值是低于第一个四分位数-1.5*IQR的任何值
这也是所描述的方法

这很容易用一个函数来概括:)我试着把下面的内容写清楚;明显的重构机会确实存在请注意,使用此常用方法,给定的样本不包含任何外围值

values = [8160,8160,6160,22684,0,0,60720,1380,1380,57128]
函数过滤器输出器(someArray){
//复制值,而不是对现有值的引用进行操作
var values=someArray.concat();
//然后分类
值。排序(函数(a,b){
返回a-b;
});
/*然后找到一个慷慨的IQR。这是慷慨的,因为如果(value.length/4)
*不是int,那么实际上你应该平均这两个元素
*一边去找q1。
*/     
var q1=数值[Math.floor((values.length/4))];
//第三季度也是如此。
var q3=数值[Math.ceil((values.length*(3/4))];
var iqr=q3-q1;
//然后找到最小值和最大值
var maxValue=q3+iqr*1.5;
var minValue=q1-iqr*1.5;
//然后过滤超出或低于这些值的任何内容。
var filteredValues=values.filter(函数(x){
返回值(x=最小值);
});
//然后返回
返回filteredvalue;
}

这是@james-peterson解决方案的改进版本,它将语法更新为当前的Javascript标准,并添加了一种更健壮的查找两个四分位数的方法(根据 )。它使用更快的方式复制阵列(有关性能比较,请参阅),并且在q1=q3时仍然有效

function filterOutliers(someArray) {  

    // Copy the values, rather than operating on references to existing values
    var values = someArray.concat();

    // Then sort
    values.sort( function(a, b) {
            return a - b;
         });

    /* Then find a generous IQR. This is generous because if (values.length / 4) 
     * is not an int, then really you should average the two elements on either 
     * side to find q1.
     */     
    var q1 = values[Math.floor((values.length / 4))];
    // Likewise for q3. 
    var q3 = values[Math.ceil((values.length * (3 / 4)))];
    var iqr = q3 - q1;

    // Then find min and max values
    var maxValue = q3 + iqr*1.5;
    var minValue = q1 - iqr*1.5;

    // Then filter anything beyond or beneath these values.
    var filteredValues = values.filter(function(x) {
        return (x <= maxValue) && (x >= minValue);
    });

    // Then return
    return filteredValues;
}
函数过滤器输出器(someArray){
if(someArray.length<4)
返回数组;
let值,q1,q3,iqr,maxValue,minValue;
values=someArray.slice().sort((a,b)=>a-b);//快速复制数组并排序
如果((values.length/4)%1==0){//find quartiles
q1=1/2*(值[(values.length/4)]+值[(values.length/4)+1];
q3=1/2*(值[(values.length*(3/4))]+值[(values.length*(3/4))+1]);
}否则{
q1=数值[数学楼层(数值长度/4+1)];
q3=数值[Math.ceil(values.length*(3/4)+1)];
}
iqr=q3-q1;
maxValue=q3+iqr*1.5;
minValue=q1-iqr*1.5;

返回值。筛选器((x)=>(x>=minValue)&&(x如果数据集包含重复的值,则此方法实际上会失败。例如
1、2、2、2、2、3、10

我和它斗争了一段时间,但后来我发现了一种叫做Grubbs'test的东西。到目前为止,它似乎是可靠的,至少在我的案例中是如此


这里有一个指向演示(和源代码)的链接:

其他两种解决方案存在一些问题。例如,由于索引错误,NaN值为q1和q3。由于索引为0,数组长度需要有-1。然后检查索引是int还是decimal,如果是decimal,则提取两个索引之间的值

function filterOutliers(someArray) {

  if(someArray.length < 4)
    return someArray;

  let values, q1, q3, iqr, maxValue, minValue;

  values = someArray.slice().sort( (a, b) => a - b);//copy array fast and sort

  if((values.length / 4) % 1 === 0){//find quartiles
    q1 = 1/2 * (values[(values.length / 4)] + values[(values.length / 4) + 1]);
    q3 = 1/2 * (values[(values.length * (3 / 4))] + values[(values.length * (3 / 4)) + 1]);
  } else {
    q1 = values[Math.floor(values.length / 4 + 1)];
    q3 = values[Math.ceil(values.length * (3 / 4) + 1)];
  }

  iqr = q3 - q1;
  maxValue = q3 + iqr * 1.5;
  minValue = q1 - iqr * 1.5;

  return values.filter((x) => (x >= minValue) && (x <= maxValue));
}
函数过滤器输出器(someArray){
if(someArray.length<4){
返回数组;
}
让value=someArray.slice().sort((a,b)=>a-b);//快速复制数组并排序
设q1=getQuantile(值,25);
设q3=getQuantile(值75);
设iqr、maxValue、minValue;
iqr=q3-q1;
maxValue=q3+iqr*1.5;
minValue=q1-iqr*1.5;

返回值.filter((x)=>(x>=minValue)和&(x这里是从给定集合中筛选较高异常值的实现。此方法遵循与上面提供的答案类似的方法

if
案例将检查收集长度,如果它是
4n
4n+1
。在这种情况下,我们需要得到两个元素的平均值才能得到四分位数

否则,在
4n+2
4n+3
的情况下,我们可以直接访问上/下四分位数


常量异常检测器=集合=>{
const size=collection.length;
让q1,q3;
如果(尺寸<2){
回收;
}
const sortedCollection=collection.slice().sort((a,b)=>a-b);
如果((大小-1)/4%1==0 | |大小/4%1==0){
q1=1/2*(分类收集[数学地板(尺寸/4)-1]+分类收集[数学地板(尺寸/4)];
q3=1/2*(分类收集[Math.ceil(尺寸*3/4)-1]+分类收集[Math.ceil(尺寸*3/4)];
}否则{
q1=分类收集[数学地板(尺寸/4)];
q3=分类收集[数学地板(尺寸*3/4)];
}
常数iqr=q3-q1;
常数maxValue=q3+iqr*1.5;
返回sortedCollection.filter(值=>value>=maxValue);
};

您可能需要检查此答案:。如果您想签出库,则有下划线。请参阅此答案以获取示例:您也可以查看此库它是否工作?我尝试了
过滤器输出器([81608160616022684,0,0607201380138057128,1000000000000])
并且它返回完全相同的数组。上面代码中有轻微的逻辑错误。过滤器应该返回(xminValue);如果q1==q3,则返回空数组。应该返回
(x=minValue)
[4421351235126601227581202350122320,172125]
没有删除
17
这怎么可能?当然
17
在这里是一个异常值?@Frank:17不是一个异常值。数组
(1st.Quadrant-1.5*(IQR))
的下限比17低得多。第二个条件对于数组长度<7的任何东西都不起作用,因为q3最终超出了界限,即
Math.ceil(7*(3/4)+1)=7
.A
Math.min
应该可以解决它,我猜在
function filterOutliers (someArray) {
    if (someArray.length < 4) {
        return someArray;
    }

    let values = someArray.slice().sort((a, b) => a - b); // copy array fast and sort

    let q1 = getQuantile(values, 25);
    let q3 = getQuantile(values, 75);

    let iqr, maxValue, minValue;
    iqr = q3 - q1;
    maxValue = q3 + iqr * 1.5;
    minValue = q1 - iqr * 1.5;

    return values.filter((x) => (x >= minValue) && (x <= maxValue));
}

function getQuantile (array, quantile) {
    // Get the index the quantile is at.
    let index = quantile / 100.0 * (array.length - 1);

    // Check if it has decimal places.
    if (index % 1 === 0) {
        return array[index];
    } else {
        // Get the lower index.
        let lowerIndex = Math.floor(index);
        // Get the remaining.
        let remainder = index - lowerIndex;
        // Add the remaining to the lowerindex value.
        return array[lowerIndex] + remainder * (array[lowerIndex + 1] - array[lowerIndex]);
    }
}