Skip to content

Instantly share code, notes, and snippets.

@kawaz
Last active August 31, 2024 04:42
Show Gist options
  • Save kawaz/1921fd02829146809203b3e7d481e30a to your computer and use it in GitHub Desktop.
Save kawaz/1921fd02829146809203b3e7d481e30a to your computer and use it in GitHub Desktop.
データ列に対してmapすると移動平均が得られるフィルタ関数。chartjs が移動平均線の描画に対応してないっぽいが、これを噛ましてやれば自力で移動平均用のデータ列が作れる。
const movingAverageFilter = (ws=3) => {
if(!Number.isInteger(ws) || ws < 1) {
throw new Error(`Invalid window size. ws must be >=1. You entered: ws=${ws}.`)
}
let win = []
let sum = 0
let pos = 0
let tail = 0
return (head) => {
sum = sum + head - tail
win[pos] = head
pos = pos < ws - 1 ? pos + 1 : 0
if(win.length < ws) {
return
}
tail = win[pos]
return sum/ws
}
}
// test
const data = [1,2,3,4,5,6,7,8,9,10];
[1,2,3,5,10].forEach(ws => {
console.log(`ws=${ws}`, data.map(movingAverageFilter(ws)))
})
const removeOutliersIqr = (windowSize = 12, thresholdFactor = 1.5) => {
// 移動平均とIQRを基に外れ値をフィルタ判定する関数を返す
const q1index = Math.floor(windowSize / 4)
const q3index = Math.floor(windowSize * 3 / 4)
return function(v, i, a) {
if (a.length < windowSize) {
return v;
} else {
const windowData = i < windowSize ? a.slice(0, windowSize) : a.slice(i - windowSize, i)
const movingAvg = windowData.reduce((a, b) => a + b, 0) / windowSize;
const sortedWindowData = windowData.slice().sort((a,b)=>a-b)
const q1 = sortedWindowData[q1index]
const q3 = sortedWindowData[q3index]
const iqr = q3 - q1
const lowerBound = movingAvg - thresholdFactor * iqr
const upperBound = movingAvg + thresholdFactor * iqr
console.log({q1index,q3index,q1,q3,iqr,lowerBound,movingAvg,upperBound,windowData,sortedWindowData})
if (v < lowerBound || v > upperBound) {
// 外れ値の場合、移動平均値を返す
return [v,movingAvg]
} else {
return v
}
}
}
}
data=[650,1002.64,1002.63,1002.58,1002.6,1002.6,1002.61,1002.61,1002.66,1002.64,1002.63,1002.63,1002.7,1002.64,1002.53,1002.53,1002.66,1002.71,1002.65,1002.61,1002.68,1002.61,1002.63];
windowSizes = [5,10]
thresholdFactors = [1.5, 3, 5, 10]
for(const tf of thresholdFactors) {
for(const ws of windowSizes) {
console.log(`ws=${ws} tf=${tf}`, data.map(removeOutliersIqr(ws, tf)))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment