【问题标题】:Calculate trendline and predict future results计算趋势线并预测未来结果
【发布时间】:2012-08-03 13:34:10
【问题描述】:

我正在为我正在开发的网站编写一些分析模块,我需要估算当前小时后的总浏览量。我有每分钟到当前分钟的数据,所以如果时间是 12:28,我将有一个看起来像这样的数组:

0: "21410"
1: "21886"
2: "21837"
3: "21895"
4: "21564"
5: "21714"
6: "21571"
7: "21324"
8: "21310"
9: "21390"
10: "21764"
11: "21598"
12: "21493"
13: "21352"
14: "21478"
15: "21058"
16: "20942"
17: "20825"
18: "21321"
19: "20950"
20: "21039"
21: "21117"
22: "20733"
23: "20773"
24: "20929"
25: "20900"
26: "20687"
27: "20999"

目前我正在这样预测小时的价值:

(60/minsSoFar)*totalSoFar

这工作得相当好,但我宁愿在数学上做得更多。我想计算迄今为止我拥有的数据的最佳拟合线,并将其投影到第 60 分钟。这将考虑加速和减速。

使用我目前使用的方法,我有效地假设趋势是一条直线。如何计算多项式或幂趋势的公式?

我是用 NodeJS 编写的,所以 JavaScript 是理想的,但我也会使用伪代码!

如果您需要,这里有一个更简单格式的数组:

[21410, 21886, 21837, 21895, 21564, 21714, 21571, 21324, 21310, 21390, 21764, 21598, 21493, 21352, 21478, 21058, 20942, 20825, 21321, 20950, 21039, 21117, 20733, 20773, 20929, 20900, 20687, 20999]

感谢您的帮助!

【问题讨论】:

标签: javascript node.js math polynomial-math trendline


【解决方案1】:

您可以对一行进行least-squares fit。

function LineFitter()
{
    this.count = 0;
    this.sumX = 0;
    this.sumX2 = 0;
    this.sumXY = 0;
    this.sumY = 0;
}

LineFitter.prototype = {
    'add': function(x, y)
    {
        this.count++;
        this.sumX += x;
        this.sumX2 += x*x;
        this.sumXY += x*y;
        this.sumY += y;
    },
    'project': function(x)
    {
        var det = this.count * this.sumX2 - this.sumX * this.sumX;
        var offset = (this.sumX2 * this.sumY - this.sumX * this.sumXY) / det;
        var scale = (this.count * this.sumXY - this.sumX * this.sumY) / det;
        return offset + x * scale;
    }
};

function linearProject(data, x)
{
    var fitter = new LineFitter();
    for (var i = 0; i < data.length; i++)
    {
        fitter.add(i, data[i]);
    }
    return fitter.project(x);
}

示例:

>>> linearProject([
        21410, 21886, 21837, 21895, 21564, 21714, 21571, 21324, 21310, 21390,
        21764, 21598, 21493, 21352, 21478, 21058, 20942, 20825, 21321, 20950,
        21039, 21117, 20733, 20773, 20929, 20900, 20687, 20999
    ], 60);
19489.614121510676

对平方多项式做类似的事情要复杂一些:

function SquareFitter()
{
    this.count = 0;
    this.sumX = 0;
    this.sumX2 = 0;
    this.sumX3 = 0;
    this.sumX4 = 0;
    this.sumY = 0;
    this.sumXY = 0;
    this.sumX2Y = 0;
}

SquareFitter.prototype = {
    'add': function(x, y)
    {
        this.count++;
        this.sumX += x;
        this.sumX2 += x*x;
        this.sumX3 += x*x*x;
        this.sumX4 += x*x*x*x;
        this.sumY += y;
        this.sumXY += x*y;
        this.sumX2Y += x*x*y;
    },
    'project': function(x)
    {
        var det = this.count*this.sumX2*this.sumX4 - this.count*this.sumX3*this.sumX3 - this.sumX*this.sumX*this.sumX4 + 2*this.sumX*this.sumX2*this.sumX3 - this.sumX2*this.sumX2*this.sumX2;
        var offset = this.sumX*this.sumX2Y*this.sumX3 - this.sumX*this.sumX4*this.sumXY - this.sumX2*this.sumX2*this.sumX2Y + this.sumX2*this.sumX3*this.sumXY + this.sumX2*this.sumX4*this.sumY - this.sumX3*this.sumX3*this.sumY;
        var scale = -this.count*this.sumX2Y*this.sumX3 + this.count*this.sumX4*this.sumXY + this.sumX*this.sumX2*this.sumX2Y - this.sumX*this.sumX4*this.sumY - this.sumX2*this.sumX2*this.sumXY + this.sumX2*this.sumX3*this.sumY;
        var accel = this.sumY*this.sumX*this.sumX3 - this.sumY*this.sumX2*this.sumX2 - this.sumXY*this.count*this.sumX3 + this.sumXY*this.sumX2*this.sumX - this.sumX2Y*this.sumX*this.sumX + this.sumX2Y*this.count*this.sumX2;
        return (offset + x*scale + x*x*accel)/det;
    }
};

function squareProject(data)
{
    var fitter = new SquareFitter();
    for (var i = 0; i < data.length; i++)
    {
        fitter.add(i, data[i]);
    }
    return fitter.project(60);
}

示例 2:

>>> squareProject([
        21410, 21886, 21837, 21895, 21564, 21714, 21571, 21324, 21310, 21390,
        21764, 21598, 21493, 21352, 21478, 21058, 20942, 20825, 21321, 20950,
        21039, 21117, 20733, 20773, 20929, 20900, 20687, 20999
    ], 60);
19282.85862700518

我可以对更高次多项式执行此操作,但表达式会变得更长。对于任意程度,您必须查看矩阵。

【讨论】:

  • 我强烈建议您使用其他语言找到一个曲线拟合库,并将您需要的内容翻译成 JavaScript,而不是尝试直接实现教科书公式。问题是教科书公式通常在数值上不稳定,也就是说它们对数字的浮点表示和实际数学数字之间的差异非常敏感。例如,如果两个数字彼此接近,任何可能涉及从另一个大数中减去一个大数的计算都可能会出现舍入误差。
  • linearProject中的“x”是什么意思?
  • @KashyapKotak x 参数是返回估计直线(或曲线)上的 y 坐标的 x 坐标。在示例中,列表索引用作 x 坐标。
猜你喜欢
  • 1970-01-01
  • 2020-01-16
  • 2018-07-18
  • 1970-01-01
  • 2021-07-25
  • 2011-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多