在分析一个事件走势的时候,一般我们会获取到这个事件系列的数据。但是,在绘制出相关的曲线的之后,我们会发现曲线的上下振动比较频繁,那是因为一些短期内的杂数据引起的。比如:
上图的原始数据获取 chartData.js,总共 2000 个点
那么,我们怎么通过事件的系列数据,得到这个事件的相关走势呢?
在进入主题前,我们先了解下 滑动窗口算法
假设给你这一些列的数据:[1,2,3,4,5,6,7,8,4,3,2,1]
,求出相邻的三个数之和最大是多少?
👌,我们有下面的思路:
2
步骤执行我们来实现下:
function getSum(arr, step) { // arr 是一维数组
// 这里没有考虑边界等问题
let sum = 0;
for(let i = 0; i < (arr.length - step + 1); i += 1) {
let tempSum = 0;
for(let j = i; j < (i+step); j += 1) {
tempSum += arr[j];
}
if(tempSum > sum) {
sum = tempSum;
}
tempSum = 0;
}
return sum;
}
let maxSum = getSum([1,2,3,4,5,6,7,8,4,3,2,1], 3);
console.log(maxSum); // 21
但是,这里的时间算法复杂度去到了 **O(n^2 )**,我们能够改善下时间复杂度吗?
窗口滑动算法 是一种基于双指针的一种思想,两个指针指向的元素之间形成一个窗口。可用于解决数组/字符串的字元素问题,用在减少嵌套循环的使用,并且用单循环代替它,减少时间复杂度。
So,我们将上面的代码更改下:
function getSumSlidingWindow(arr, step) {
// 这里同样没有考虑边界等问题
let sum = 0;
for(let i = 0; i < step; i++) {
sum += arr[i];
}
let tempSum = sum;
for(let i = step; i < arr.length; i++) {
tempSum += arr[i] - arr[i - step];
if(tempSum > sum) {
sum = tempSum;
}
}
return sum;
}
let maxSum = getSumSlidingWindow([1,2,3,4,5,6,7,8,4,3,2,1], 3);
console.log(maxSum); // 21
窗口滑动算法的时间复杂度去到了 **O(n)**。
接下来,我们使用移动滑动窗口,来进行 21
个点为一个窗口的 MA
过滤算法。
MA -> Moving Average 移动平均
顾名思义,移动平均,就是将移动窗口中的值进行求平均,我们可以通过下面的代码进行数据处理:
let maDatas = [];
// 滑动窗口
function filterAverage(signal, k) { // k 应该为奇数
let sum = 0;
for(let i = 0; i < k; i++) {
sum += signal[i];
if(i < (k-1) / 2) { // 本例中,我们忽略数组的前 10 个数据
maDatas.push(null);
}
}
maDatas.push(sum / k);
for(let i = k; i < signal.length; i++) {
sum += signal[i] - signal[i - k];
maDatas.push(sum / k); // 本例中,忽略数组的后 10 个数据
}
}
filterAverage(rawDatas, 21);
数据量大的时候,我们忽略些前后的数据,影响不大,如果你觉得不应该忽略的话,那你需要对这些数据进行特殊的处理。比如,第一数据,平均值是第一个数据的值,第二个数据,平均值是第一个数据+第二个数据的平均值,以此类推
通过上面 filterAverage
方法,我们可以计算出移动平均过滤后的数值,绘制出曲线见下图 ma
。
通过图,我们可能没能感受到 ma
的图表的平滑度,我们结合 求解波值的波峰和波谷「Javascript」 来求一下两者的波峰和波谷:
原始数据: 波峰 => 430; 波谷 => 430
MA 数据: 波峰 => 64; 波谷 => 65
思考🤔:那么,我们可以通过调整滑动窗口,算出股票中的 5
日均线,10
日均线,20
日均线和 60
日均线。
我们可以通过移动平均过滤算法预测接下来一段时间的走势。You can think in deeply。