在数组中查找并不总是一致的模式
Finding a pattern in an array that is not always consistant
我有一个有序的十进制数数据集。这些数据总是相似的——但并不总是相同的。预期数据是一些 0 - 5 个大数字,然后是几个 (10 - 90) 个平均数字,然后是较小的数字。在某些情况下,可能会在平均数中混入大量数字'请参阅以下数组。
let expectedData = [35.267,9.267,9.332,9.186,9.220,9.141,9.107,9.114,9.098,9.181,9.220,4.012,0.132];
let expectedData = [35.267,32.267,9.267,9.332,9.186,9.220,9.141,9.107,30.267,9.114,9.098,9.181,9.220,4.012,0.132];
我正在尝试通过获取平均值来分析数据,而不是前面的高数字和背面的低数字。中间 high/low 可以保持在平均水平。我在下面有一个部分解决方案。现在我有点蛮力,但解决方案并不完美。在较小的数据集上,第一个平均计算受较大数字的影响。
我的问题是:有没有办法处理这类问题,即识别数字数组中的模式?
我的算法是:
- 获取数组的平均值
- 计算 above/below 平均值
- 移除前 (n) 个高于平均值的元素
- 删除低于平均水平的结束元素
- 重新计算平均值
在 JavaScript 我有:(这是部分遗漏低于平均水平)
let total= expectedData.reduce((rt,cur)=> {return rt+cur;}, 0);
let avg = total/expectedData.length;
let aboveAvg = avg*0.1+avg;
let remove = -1;
for(let k=0;k<expectedData.length;k++) {
if(expectedData[k] > aboveAvg) {
remove=k;
} else {
if(k==0) {
remove = -1;//no need to remove
}
//break because we don't want large values from middle removed.
break;
}
}
if(remove >= 0 ) {
//remove front above average
expectedData.splice(0,remove+1);
}
//remove belows
//recalculate average
首先,我会尝试使用滑动 window 和滞后/带通滤波器来检测高值峰值。
然后,当你的滑动 windows 前进时,你可以将之前的第一个值(现在是分析的最后一个值)添加到全局总和,并将总值的数量加 1。
当您遇到峰值(=导致滞后移动或溢出频带滤波器的东西)时,您可以删除这些值(可能代价高昂),或者更好的是,将值设置为 NaN
所以你可以安全地忽略它。
您应该在滑动 window 中继续计算滑动平均值,以便能够 auto-correct hysteresis/band 过滤器,因此它只会拒绝峰值的起始值(结束值是下一个的起始值),但一旦值稳定到一个新的水平,值将再次保持。
滑动的大小window将设置需要保留多少连续的“稳定”值,或者换句话说,当你达到一个新的水平时,有多少不稳定的值被拒绝。
我相信您正在寻找一些离群值检测算法。 Stack overflow 上已经有一堆与此相关的问题。
但是,每种异常值检测算法都有其优点。
以下是其中的一些
https://mathworld.wolfram.com/Outlier.html
高异常值是超出第三个四分位数 + 1.5 * inter-quartile 范围 (IQR)
的任何值
低异常值是低于第一个四分位数的任何值 - 1.5 * IQR
格拉布斯试验
- 您可以查看它如何符合您的期望here
除了这两个,还有一个比较计算器here。您可以访问此网站以根据需要使用其他算法。
为此,您可以检查值的众数(四舍五入),然后取众数附近一定范围内的所有数字。该范围可以取自数据本身,例如取 max - min
值的 10%
。这有助于您过滤数据。您可以 select 满足您需求的百分比。像这样:
let expectedData = [35.267,9.267,9.332,9.186,9.220,9.141,9.107,9.114,9.098,9.181,9.220,4.012,0.132];
expectedData.sort((a, b) => a - b);
/// Get the range of the data
const RANGE = expectedData[ expectedData.length - 1 ] - expectedData[0];
const WINDOW = 0.1; /// Window of selection 10% from left and right
/// Frequency of each number
let dist = expectedData.reduce((acc, e) => (acc[ Math.floor(e) ] = (acc[ Math.floor(e) ] || 0) + 1, acc), {});
let mode = +Object.entries(dist).sort((a, b) => b[1] - a[1])[0][0];
let newData = expectedData.filter(e => mode - RANGE * WINDOW <= e && e <= mode + RANGE * WINDOW);
console.log(newData);
我有一个有序的十进制数数据集。这些数据总是相似的——但并不总是相同的。预期数据是一些 0 - 5 个大数字,然后是几个 (10 - 90) 个平均数字,然后是较小的数字。在某些情况下,可能会在平均数中混入大量数字'请参阅以下数组。
let expectedData = [35.267,9.267,9.332,9.186,9.220,9.141,9.107,9.114,9.098,9.181,9.220,4.012,0.132];
let expectedData = [35.267,32.267,9.267,9.332,9.186,9.220,9.141,9.107,30.267,9.114,9.098,9.181,9.220,4.012,0.132];
我正在尝试通过获取平均值来分析数据,而不是前面的高数字和背面的低数字。中间 high/low 可以保持在平均水平。我在下面有一个部分解决方案。现在我有点蛮力,但解决方案并不完美。在较小的数据集上,第一个平均计算受较大数字的影响。
我的问题是:有没有办法处理这类问题,即识别数字数组中的模式?
我的算法是:
- 获取数组的平均值
- 计算 above/below 平均值
- 移除前 (n) 个高于平均值的元素
- 删除低于平均水平的结束元素
- 重新计算平均值
在 JavaScript 我有:(这是部分遗漏低于平均水平)
let total= expectedData.reduce((rt,cur)=> {return rt+cur;}, 0);
let avg = total/expectedData.length;
let aboveAvg = avg*0.1+avg;
let remove = -1;
for(let k=0;k<expectedData.length;k++) {
if(expectedData[k] > aboveAvg) {
remove=k;
} else {
if(k==0) {
remove = -1;//no need to remove
}
//break because we don't want large values from middle removed.
break;
}
}
if(remove >= 0 ) {
//remove front above average
expectedData.splice(0,remove+1);
}
//remove belows
//recalculate average
首先,我会尝试使用滑动 window 和滞后/带通滤波器来检测高值峰值。
然后,当你的滑动 windows 前进时,你可以将之前的第一个值(现在是分析的最后一个值)添加到全局总和,并将总值的数量加 1。
当您遇到峰值(=导致滞后移动或溢出频带滤波器的东西)时,您可以删除这些值(可能代价高昂),或者更好的是,将值设置为 NaN
所以你可以安全地忽略它。
您应该在滑动 window 中继续计算滑动平均值,以便能够 auto-correct hysteresis/band 过滤器,因此它只会拒绝峰值的起始值(结束值是下一个的起始值),但一旦值稳定到一个新的水平,值将再次保持。
滑动的大小window将设置需要保留多少连续的“稳定”值,或者换句话说,当你达到一个新的水平时,有多少不稳定的值被拒绝。
我相信您正在寻找一些离群值检测算法。 Stack overflow 上已经有一堆与此相关的问题。
但是,每种异常值检测算法都有其优点。
以下是其中的一些
https://mathworld.wolfram.com/Outlier.html
高异常值是超出第三个四分位数 + 1.5 * inter-quartile 范围 (IQR)
的任何值低异常值是低于第一个四分位数的任何值 - 1.5 * IQR
格拉布斯试验
- 您可以查看它如何符合您的期望here
除了这两个,还有一个比较计算器here。您可以访问此网站以根据需要使用其他算法。
为此,您可以检查值的众数(四舍五入),然后取众数附近一定范围内的所有数字。该范围可以取自数据本身,例如取 max - min
值的 10%
。这有助于您过滤数据。您可以 select 满足您需求的百分比。像这样:
let expectedData = [35.267,9.267,9.332,9.186,9.220,9.141,9.107,9.114,9.098,9.181,9.220,4.012,0.132];
expectedData.sort((a, b) => a - b);
/// Get the range of the data
const RANGE = expectedData[ expectedData.length - 1 ] - expectedData[0];
const WINDOW = 0.1; /// Window of selection 10% from left and right
/// Frequency of each number
let dist = expectedData.reduce((acc, e) => (acc[ Math.floor(e) ] = (acc[ Math.floor(e) ] || 0) + 1, acc), {});
let mode = +Object.entries(dist).sort((a, b) => b[1] - a[1])[0][0];
let newData = expectedData.filter(e => mode - RANGE * WINDOW <= e && e <= mode + RANGE * WINDOW);
console.log(newData);