谷歌不是我的朋友 - 自从我在大学的统计课程已经很长时间了......我需要计算一个图表上趋势线的起点和终点 - 有一个简单的方法吗?(在C#中工作,但无论什么语言适合你)
感谢所有人的帮助 - 我已经离开这个问题了几天而且刚刚回到它 - 能够将它拼凑在一起 - 不是最优雅的代码,但它适用于我的目的 - 我想分享如果其他人遇到这个问题:
public class Statistics { public Trendline CalculateLinearRegression(int[] values) { var yAxisValues = new List(); var xAxisValues = new List (); 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 xAxisValues; private readonly IList yAxisValues; private int count; private int xAxisValuesSum; private int xxSum; private int xySum; private int yAxisValuesSum; public Trendline(IList yAxisValues, IList 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; } }
好的,这是我最好的伪数学:
你的线的等式是:
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是点数
鉴于趋势线是直的,通过选择任意两个点并计算来找到斜率:
(A)斜率=(y1-y2)/(x1-x2)
然后你需要找到该行的偏移量.该行由以下等式指定:
(B)y =偏移+斜率*x
所以你需要解决偏移问题.选择线上的任何点,并求解偏移量:
(C)偏移= y - (斜率*x)
现在,您可以将斜率和偏移量插入到线方程(B)中,并使用定义线的方程式.如果你的线路有噪声,你必须决定平均算法,或者使用某种曲线拟合.
如果你的线不直,你需要看看曲线拟合,或最小二乘拟合 - 非平凡,但可以.如果你知道你喜欢什么样的拟合,你会在最小二乘拟合网页(指数,多项式等)的底部看到各种类型的曲线拟合.
此外,如果这是一次性,使用Excel.
这是Bedwyr Humphreys答案的一个非常快速(和半肮脏)的实现.该接口也应该与@matt的答案兼容,但是使用更多的IEnumerable概念来decimal
代替int
并使用更多IEnumerable概念,以便更容易使用和阅读.
Slope
是b
,Intercept
是a
public class Trendline { public Trendline(IListyAxisValues, IList xAxisValues) : this(yAxisValues.Select((t, i) => new Tuple (xAxisValues[i], t))) { } public Trendline(IEnumerable > 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; } }