如何计算图表的趋势线?

时间:2008-09-04 05:41:07

标签: c# math graph

谷歌不是我的朋友 - 自从我在大学的统计课程已经很长时间了......我需要在图表上计算趋势线的起点和终点 - 是否有一种简单的方法可以做到这一点? (在C#中工作,但无论什么语言适合你)

12 个答案:

答案 0 :(得分:33)

感谢所有人的帮助 - 我已经离开了这个问题几天而且刚刚回到它 - 能够将它拼凑在一起 - 而不是最优雅的代码,但它适用于我的目的 - 我想'如果其他人遇到此问题,请分享:

public class Statistics
{
    public Trendline CalculateLinearRegression(int[] values)
    {
        var yAxisValues = new List<int>();
        var xAxisValues = new List<int>();

        for (int i = 0; i < values.Length; i++)
        {
            yAxisValues.Add(values[i]);
            xAxisValues.Add(i + 1);
        }

        return new Trendline(yAxisValues, xAxisValues);
    }
}

public class Trendline
{
    private readonly IList<int> xAxisValues;
    private readonly IList<int> yAxisValues;
    private int count;
    private int xAxisValuesSum;
    private int xxSum;
    private int xySum;
    private int yAxisValuesSum;

    public Trendline(IList<int> yAxisValues, IList<int> xAxisValues)
    {
        this.yAxisValues = yAxisValues;
        this.xAxisValues = xAxisValues;

        this.Initialize();
    }

    public int Slope { get; private set; }
    public int Intercept { get; private set; }
    public int Start { get; private set; }
    public int End { get; private set; }

    private void Initialize()
    {
        this.count = this.yAxisValues.Count;
        this.yAxisValuesSum = this.yAxisValues.Sum();
        this.xAxisValuesSum = this.xAxisValues.Sum();
        this.xxSum = 0;
        this.xySum = 0;

        for (int i = 0; i < this.count; i++)
        {
            this.xySum += (this.xAxisValues[i]*this.yAxisValues[i]);
            this.xxSum += (this.xAxisValues[i]*this.xAxisValues[i]);
        }

        this.Slope = this.CalculateSlope();
        this.Intercept = this.CalculateIntercept();
        this.Start = this.CalculateStart();
        this.End = this.CalculateEnd();
    }

    private int CalculateSlope()
    {
        try
        {
            return ((this.count*this.xySum) - (this.xAxisValuesSum*this.yAxisValuesSum))/((this.count*this.xxSum) - (this.xAxisValuesSum*this.xAxisValuesSum));
        }
        catch (DivideByZeroException)
        {
            return 0;
        }
    }

    private int CalculateIntercept()
    {
        return (this.yAxisValuesSum - (this.Slope*this.xAxisValuesSum))/this.count;
    }

    private int CalculateStart()
    {
        return (this.Slope*this.xAxisValues.First()) + this.Intercept;
    }

    private int CalculateEnd()
    {
        return (this.Slope*this.xAxisValues.Last()) + this.Intercept;
    }
}

答案 1 :(得分:27)

好的,这是我最好的伪数学:

您的行的等式是:

Y = a + bX

其中:

b =(sum(x * y) - sum(x)sum(y)/ n)/(sum(x ^ 2) - sum(x)^ 2 / n)

a = sum(y)/ n-b(sum(x)/ n)

其中sum(xy)是所有x * y等的总和。我承认并不是特别清楚,但是如果没有sigma符号,它是最好的:)

...现在增加了Sigma

b =(Σ(xy) - (ΣxΣy)/ n)/(Σ(x ^ 2) - (Σx)^ 2 / n)

a =(Σy)/ n - b((Σx)/ n)

其中Σ(xy)是所有x * y等的总和,n是点数

答案 2 :(得分:15)

鉴于趋势线是直的,通过选择任意两个点并计算:

来找到斜率

(A)斜率=(y1-y2)/(x1-x2)

然后你需要找到该行的偏移量。该行由以下等式指定:

(B)y =偏移+斜率* x

所以你需要解决偏移问题。选择线上的任何点,并求解偏移量:

(C)offset = y - (slope * x)

现在,您可以将斜率和偏移量插入到线方程(B)中,并使用定义线的方程式。如果您的线路有噪声,您必须决定平均算法,或使用某种曲线拟合。

如果您的直线不直,那么您需要查看Curve fittingLeast Squares Fitting - 非常简单但可行。如果你知道你喜欢什么样的拟合,你会在最小二乘拟合网页(指数,多项式等)的底部看到各种类型的曲线拟合。

此外,如果这是一次性的,请使用Excel。

答案 3 :(得分:15)

这是Bedwyr Humphreys's answer的一个非常快速(和半脏)的实现。该界面也应与@matt的答案兼容,但使用decimal代替int,并使用更多IEnumerable概念,以便更容易使用和阅读。

SlopebIntercepta

public class Trendline
{
    public Trendline(IList<decimal> yAxisValues, IList<decimal> xAxisValues)
        : this(yAxisValues.Select((t, i) => new Tuple<decimal, decimal>(xAxisValues[i], t)))
    { }
    public Trendline(IEnumerable<Tuple<Decimal, Decimal>> data)
    {
        var cachedData = data.ToList();

        var n = cachedData.Count;
        var sumX = cachedData.Sum(x => x.Item1);
        var sumX2 = cachedData.Sum(x => x.Item1 * x.Item1);
        var sumY = cachedData.Sum(x => x.Item2);
        var sumXY = cachedData.Sum(x => x.Item1 * x.Item2);

        //b = (sum(x*y) - sum(x)sum(y)/n)
        //      / (sum(x^2) - sum(x)^2/n)
        Slope = (sumXY - ((sumX * sumY) / n))
                    / (sumX2 - (sumX * sumX / n));

        //a = sum(y)/n - b(sum(x)/n)
        Intercept = (sumY / n) - (Slope * (sumX / n));

        Start = GetYValue(cachedData.Min(a => a.Item1));
        End = GetYValue(cachedData.Max(a => a.Item1));
    }

    public decimal Slope { get; private set; }
    public decimal Intercept { get; private set; }
    public decimal Start { get; private set; }
    public decimal End { get; private set; }

    public decimal GetYValue(decimal xValue)
    {
        return Intercept + Slope * xValue;
    }
}

答案 4 :(得分:3)

关于先前的答案

如果(B)y =偏移+斜率* x

然后(C)偏移= y /(斜率* x)错误

(C)应该是:

偏移= y-(斜率* x)

请参阅: http://zedgraph.org/wiki/index.php?title=Trend

答案 5 :(得分:2)

如果您有权访问Excel,请查看“帮助”中“函数参考”的“统计函数”部分。对于直线最佳拟合,您需要SLOPE和INTERCEPT,方程式就在那里。

哦,坚持下去,他们也在网上定义:http://office.microsoft.com/en-us/excel/HP052092641033.aspx用于SLOPE,还有一个指向INTERCEPT的链接。当然,这假设MS不移动页面,在这种情况下尝试谷歌搜索类似“SLOPE INTERCEPT EQUATION Excel site:microsoft.com”之类的内容 - 给出的链接刚才是第三个。

答案 6 :(得分:1)

这是我计算斜率的方式: 资料来源:http://classroom.synonym.com/calculate-trendline-2709.html

class Program
    {
        public double CalculateTrendlineSlope(List<Point> graph)
        {
            int n = graph.Count;
            double a = 0;
            double b = 0;
            double bx = 0;
            double by = 0;
            double c = 0;
            double d = 0;
            double slope = 0;

            foreach (Point point in graph)
            {
                a += point.x * point.y;
                bx = point.x;
                by = point.y;
                c += Math.Pow(point.x, 2);
                d += point.x;
            }
            a *= n;
            b = bx * by;
            c *= n;
            d = Math.Pow(d, 2);

            slope = (a - b) / (c - d);
            return slope;
        }
    }

    class Point
    {
        public double x;
        public double y;
    }

答案 7 :(得分:1)

这就是我最终使用的。

public class DataPoint<T1,T2>
{
    public DataPoint(T1 x, T2 y)
    {
        X = x;
        Y = y;
    }

    [JsonProperty("x")]
    public T1 X { get; }

    [JsonProperty("y")]
    public T2 Y { get; }
}

public class Trendline
{
    public Trendline(IEnumerable<DataPoint<long, decimal>> dataPoints)
    {
        int count = 0;
        long sumX = 0;
        long sumX2 = 0;
        decimal sumY = 0;
        decimal sumXY = 0;

        foreach (var dataPoint in dataPoints)
        {
            count++;
            sumX += dataPoint.X;
            sumX2 += dataPoint.X * dataPoint.X;
            sumY += dataPoint.Y;
            sumXY += dataPoint.X * dataPoint.Y;
        }

        Slope = (sumXY - ((sumX * sumY) / count)) / (sumX2 - ((sumX * sumX) / count));
        Intercept = (sumY / count) - (Slope * (sumX / count));
    }

    public decimal Slope { get; private set; }
    public decimal Intercept { get; private set; }
    public decimal Start { get; private set; }
    public decimal End { get; private set; }

    public decimal GetYValue(decimal xValue)
    {
        return Slope * xValue + Intercept;
    }
}

我的数据集在x轴上使用Unix时间戳,在y上使用十进制。更改这些数据类型以适合您的需求。为了求出最佳性能,我会一次迭代地进行所有求和计算。

答案 8 :(得分:0)

非常感谢您的解决方案,我正在摸不着头脑 以下是我在Excel中应用解决方案的方法 我成功地使用了MUHD在Excel中给出的两个功能:
a =(sum(x * y) - sum(x)sum(y)/ n)/(sum(x ^ 2) - sum(x)^ 2 / n)
b = sum(y)/ n-b(sum(x)/ n)
(小心我的a和b是b和MUHD的解决方案)
- 制作4列,例如:
  注意:我的值y值在B3:B17,所以我有n = 15;
      我的x值是1,2,3,4 ... 15   1. B栏:已知的x's   2. C栏:已知的y   3. D栏:计算出的趋势线
  4. E列:B值* C值(E3 = B3 * C3,E4 = B4 * C4,......,E17 = B17 * C17)
  5.列F:x平方值
然后我将列B,C和E相加,对于我来说,总和在第18行,所以我将B18作为X的总和,C18作为Y的总和,E18作为X * Y的总和,F18作为平方和。
要计算a,请在任何单元格中输入以下公式(对我来说是F35):
F35 =(E18-(B18 * C18)/ 15)/(F18-(B18 * B18)/ 15)
计算b(在F36中为我计算):
F36 = C18 / 15-F35 *(B18 / 15)
D列值,根据y = ax + b计算趋势线:
D3 = $ F $ 35 * B3 + $ F $ 36,D4 = $ F $ 35 * B4 + $ F $ 36等等(直到D17为止)。

选择列数据(C2:D17)以生成图形 HTH。

答案 9 :(得分:0)

如果任何人都需要JS代码来计算图形上许多点的趋势线,那么最终这对我们有用:

/**@typedef {{
 * x: Number;
 * y:Number;
 * }} Point
 * @param {Point[]} data
 * @returns {Function} */
function _getTrendlineEq(data) {
    const xySum = data.reduce((acc, item) => {
        const xy = item.x * item.y
        acc += xy
        return acc
    }, 0)
    const xSum = data.reduce((acc, item) => {
        acc += item.x
        return acc
    }, 0)
    const ySum = data.reduce((acc, item) => {
        acc += item.y
        return acc
    }, 0)
    const aTop = (data.length * xySum) - (xSum * ySum)
    const xSquaredSum = data.reduce((acc, item) => {
        const xSquared = item.x * item.x
        acc += xSquared
        return acc
    }, 0)
    const aBottom = (data.length * xSquaredSum) - (xSum * xSum)
    const a = aTop / aBottom
    const bTop = ySum - (a * xSum)
    const b = bTop / data.length
    return function trendline(x) {
        return a * x + b
    }
}

它需要一个(x,y)点的数组并在给定x的情况下返回y的函数 玩得开心:)

答案 10 :(得分:0)

这是golang中的一个有效示例。我四处搜索并找到了此页面,并将其转换为我需要的内容。希望其他人可以发现它有用。

// https://classroom.synonym.com/calculate-trendline-2709.html
package main

import (
    "fmt"
    "math"
)

func main() {

    graph := [][]float64{
        {1, 3},
        {2, 5},
        {3, 6.5},
    }

    n := len(graph)

    // get the slope
    var a float64
    var b float64
    var bx float64
    var by float64
    var c float64
    var d float64
    var slope float64

    for _, point := range graph {

        a += point[0] * point[1]
        bx += point[0]
        by += point[1]
        c += math.Pow(point[0], 2)
        d += point[0]

    }

    a *= float64(n)           // 97.5
    b = bx * by               // 87
    c *= float64(n)           // 42
    d = math.Pow(d, 2)        // 36
    slope = (a - b) / (c - d) // 1.75

    // calculating the y-intercept (b) of the Trendline
    var e float64
    var f float64

    e = by                            // 14.5
    f = slope * bx                    // 10.5
    intercept := (e - f) / float64(n) // (14.5 - 10.5) / 3 = 1.3

    // output
    fmt.Println(slope)
    fmt.Println(intercept)

}

答案 11 :(得分:0)

我将 Matt 的代码转换为 Java,这样我就可以在 Android 中通过 MPAndroidChart 库使用它。还使用双精度值代替整数值:

ArrayList<Entry> yValues2 = new ArrayList<>();

ArrayList<Double > xAxisValues = new ArrayList<Double>();
ArrayList<Double> yAxisValues = new ArrayList<Double>();

for (int i = 0; i < readings.size(); i++)
{
    r = readings.get(i);
    yAxisValues.add(r.value);
    xAxisValues.add((double)i + 1);
}

TrendLine tl = new TrendLine(yAxisValues, xAxisValues);

//Create the y values for the trend line
double currY = tl.Start;
for (int i = 0; i < readings.size(); ++ i) {
    yValues2.add(new Entry(i, (float) currY));
    currY = currY + tl.Slope;
}

...

public class TrendLine
{
    private ArrayList<Double> xAxisValues = new ArrayList<Double>();
    private ArrayList<Double> yAxisValues = new ArrayList<Double>();

    private int count;
    private double xAxisValuesSum;
    private double xxSum;
    private double xySum;
    private double yAxisValuesSum;

    public TrendLine(ArrayList<Double> yAxisValues, ArrayList<Double> xAxisValues)
    {
        this.yAxisValues = yAxisValues;
        this.xAxisValues = xAxisValues;

        this.Initialize();
    }

    public double Slope;
    public double Intercept;
    public double Start;
    public double End;

    private double getArraySum(ArrayList<Double> arr) {
        double sum = 0;
        for (int i = 0; i < arr.size(); ++i) {
            sum = sum + arr.get(i);
        }
        return sum;
    }
    private void Initialize()
    {
        this.count = this.yAxisValues.size();
        this.yAxisValuesSum = getArraySum(this.yAxisValues);
        this.xAxisValuesSum = getArraySum(this.xAxisValues);
        this.xxSum = 0;
        this.xySum = 0;

        for (int i = 0; i < this.count; i++)
        {
            this.xySum += (this.xAxisValues.get(i)*this.yAxisValues.get(i));
            this.xxSum += (this.xAxisValues.get(i)*this.xAxisValues.get(i));
        }

        this.Slope = this.CalculateSlope();
        this.Intercept = this.CalculateIntercept();
        this.Start = this.CalculateStart();
        this.End = this.CalculateEnd();
    }

    private double CalculateSlope()
    {
        try
        {
            return ((this.count*this.xySum) - (this.xAxisValuesSum*this.yAxisValuesSum))/((this.count*this.xxSum) - (this.xAxisValuesSum*this.xAxisValuesSum));
        }
        catch (Exception e)
        {
            return 0;
        }
    }

    private double CalculateIntercept()
    {
        return (this.yAxisValuesSum - (this.Slope*this.xAxisValuesSum))/this.count;
    }

    private double CalculateStart()
    {
        return (this.Slope*this.xAxisValues.get(0)) + this.Intercept;
    }

    private double CalculateEnd()
    {
        return (this.Slope*this.xAxisValues.get(this.xAxisValues.size()-1)) + this.Intercept;
    }
}