values = [8160,8160,6160,22684,0,0,60720,1380,1380,57128]
如何移除像0、57218、60720和22684这样的异常值?
是否有可以完成此操作的库?
values = [8160,8160,6160,22684,0,0,60720,1380,1380,57128]
如何移除像0、57218、60720和22684这样的异常值?
是否有可以完成此操作的库?
这完全取决于您对“异常值”是什么的解释。一个常见的方法:
这也是Wolfram的Mathworld所描述的方法。
这可以轻松地封装在一个函数中 :) 我已尽力清晰地编写以下内容;显然存在重构的机会。请注意,在使用这种常见方法时,样本中没有包含任何异常值。
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;
}
filterOutliers([8160,8160,6160,22684,0,0,60720,1380,1380,57128, 1000000000000])
,它返回的是完全相同的数组。 - Pablo(x <= maxValue) && (x >= minValue)
。 - Timo Kähkönen[4421, 3512, 5126, 6012, 7581, 2023, 5012, 2320, 17, 2125]
没有移除 17
,这是怎么回事呢?难道 17
在这里是一个异常值吗? - Frankfunction 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));
}
Math.ceil(7 * (3/4) + 1) = 7
。我猜应该使用Math.min
来解决这个问题。 - Dominicq3
将是NaN
,因为values[(values.length * (3 / 4)) + 1]
指向空。因此,如果长度<=4,则应该退出。 - Dominic我在其他两种解决方案中遇到了一些问题。由于索引错误,在q1和q3中有NaN值的问题。数组长度需要减1,因为索引从0开始。然后检查索引是否为整数或小数,在小数的情况下,提取两个索引之间的值。
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]);
}
}
const outlierDetector = collection => {
const size = collection.length;
let q1, q3;
if (size < 2) {
return collection;
}
const sortedCollection = collection.slice().sort((a, b) => a - b);
if ((size - 1) / 4 % 1 === 0 || size / 4 % 1 === 0) {
q1 = 1 / 2 * (sortedCollection[Math.floor(size / 4) - 1] + sortedCollection[Math.floor(size / 4)]);
q3 = 1 / 2 * (sortedCollection[Math.ceil(size * 3 / 4) - 1] + sortedCollection[Math.ceil(size * 3 / 4)]);
} else {
q1 = sortedCollection[Math.floor(size / 4)];
q3 = sortedCollection[Math.floor(size * 3 / 4)];
}
const iqr = q3 - q1;
const maxValue = q3 + iqr * 1.5;
return sortedCollection.filter(value => value >= maxValue);
};
如果你的数据集包含重复值,那么这种方法实际上会失败。例如:1, 2, 2, 2, 2, 2, 3, 10
。
我曾经为此苦苦挣扎,但后来我发现了一种叫做 Grubbs 测试的东西。到目前为止,在我的情况下它似乎是可靠的。
这里有一个演示链接(和源代码):http://xcatliu.com/grubbs/