C# 如何计算图表的趋势线?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43224/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I calculate a trendline for a graph?
提问by matt
Google is not being my friend - it's been a long time since my stats class in college...I need to calculate the start and end points for a trendline on a graph - is there an easy way to do this? (working in C# but whatever language works for you)
谷歌不是我的朋友 - 自从我在大学上统计课以来已经很长时间了......我需要计算图表上趋势线的起点和终点 - 有没有简单的方法来做到这一点?(在 C# 中工作,但任何语言都适合您)
采纳答案by Adam Davis
Given that the trendline is straight, find the slope by choosing any two points and calculating:
鉴于趋势线是直的,通过选择任意两点并计算得出斜率:
(A) slope = (y1-y2)/(x1-x2)
(A) 斜率 = (y1-y2)/(x1-x2)
Then you need to find the offset for the line. The line is specified by the equation:
然后您需要找到该行的偏移量。该线由以下等式指定:
(B) y = offset + slope*x
(B) y = 偏移量 + 斜率*x
So you need to solve for offset. Pick any point on the line, and solve for offset:
所以你需要解决偏移量。选取线上的任意点,并求解偏移:
(C) offset = y - (slope*x)
(C) offset = y - (slope*x)
Now you can plug slope and offset into the line equation (B) and have the equation that defines your line. If your line has noise you'll have to decide on an averaging algorithm, or use curve fitting of some sort.
现在,您可以将斜率和偏移量插入到直线方程 (B) 中,并获得定义直线的方程。如果您的线路有噪音,您将不得不决定采用平均算法,或使用某种曲线拟合。
If your line isn't straight then you'll need to look into Curve fitting, or Least Squares Fitting- non trivial, but do-able. You'll see the various types of curve fitting at the bottom of the least squares fitting webpage (exponential, polynomial, etc) if you know what kind of fit you'd like.
如果您的线条不直,那么您需要研究Curvefitting或Least Squares Fitting- 非平凡,但可行。如果您知道自己想要什么样的拟合,您将在最小二乘拟合网页(指数、多项式等)的底部看到各种类型的曲线拟合。
Also, if this is a one-off, use Excel.
此外,如果这是一次性的,请使用 Excel。
回答by blank
OK, here's my best pseudo math:
好的,这是我最好的伪数学:
The equation for your line is:
你的线的方程是:
Y = a + bX
Y = a + bX
Where:
在哪里:
b = (sum(x*y) - sum(x)sum(y)/n) / (sum(x^2) - sum(x)^2/n)
b = (sum(x*y) - sum(x)sum(y)/n) / (sum(x^2) - sum(x)^2/n)
a = sum(y)/n - b(sum(x)/n)
a = sum(y)/n - b(sum(x)/n)
Where sum(xy) is the sum of all x*y etc. Not particularly clear I concede, but it's the best I can do without a sigma symbol :)
其中 sum(xy) 是所有 x*y 等的总和。我承认不是特别清楚,但这是我可以在没有 sigma 符号的情况下做的最好的事情:)
... and now with added Sigma
...现在添加了Sigma
b = (Σ(xy) - (ΣxΣy)/n) / (Σ(x^2) - (Σx)^2/n)
b = (Σ(xy) - (ΣxΣy)/n) / (Σ(x^2) - (Σx)^2/n)
a = (Σy)/n - b((Σx)/n)
a = (Σy)/n - b((Σx)/n)
Where Σ(xy) is the sum of all x*y etc. and n is the number of points
其中 Σ(xy) 是所有 x*y 等的总和,n 是点数
回答by Mike Woodhouse
If you have access to Excel, look in the "Statistical Functions" section of the Function Reference within Help. For straight-line best-fit, you need SLOPE and INTERCEPT and the equations are right there.
如果您有权访问 Excel,请查看帮助中函数参考的“统计函数”部分。对于直线最佳拟合,您需要 SLOPE 和 INTERCEPT,方程就在那里。
Oh, hang on, they're also defined online here: http://office.microsoft.com/en-us/excel/HP052092641033.aspxfor SLOPE, and there's a link to INTERCEPT. OF course, that assumes MS don't move the page, in which case try Googling for something like "SLOPE INTERCEPT EQUATION Excel site:microsoft.com" - the link given turned out third just now.
哦,等等,它们也在此处在线定义:http: //office.microsoft.com/en-us/excel/HP052092641033.aspxfor SLOPE,还有一个指向 INTERCEPT 的链接。当然,这假设 MS 不移动页面,在这种情况下,请尝试在谷歌上搜索“斜率截距方程 Excel 站点:microsoft.com”之类的内容 - 给出的链接现在排在第三位。
回答by matt
Thanks to all for your help - I was off this issue for a couple of days and just came back to it - was able to cobble this together - not the most elegant code, but it works for my purposes - thought I'd share if anyone else encounters this issue:
感谢所有人的帮助 - 我已经离开这个问题几天了,然后又回到了它 - 能够将它拼凑在一起 - 不是最优雅的代码,但它适用于我的目的 - 我想我会分享如果其他人遇到这个问题:
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;
}
}
回答by matt
Regarding a previous answer
关于之前的回答
if (B) y = offset + slope*x
如果(B) y = 偏移量 + 斜率*x
then (C) offset = y/(slope*x)is wrong
那么(C) offset = y/(slope*x)是错误的
(C) should be:
(C) 应该是:
offset = y-(slope*x)
偏移量 = y-(斜率 * x)
回答by franchsesko
Thank You so much for the solution, I was scratching my head.
Here's how I applied the solution in Excel.
I successfully used the two functions given by MUHD in 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)
(careful my a and b are the b and a in MUHD's solution).
- Made 4 columns, for example:
NB: my values y values are in B3:B17, so I have n=15;
my x values are 1,2,3,4...15.
1. Column B: Known x's
2. Column C: Known y's
3. Column D: The computed trend line
4. Column E: B values * C values (E3=B3*C3, E4=B4*C4, ..., E17=B17*C17)
5. Column F: x squared values
I then sum the columns B,C and E, the sums go in line 18 for me, so I have B18 as sum of Xs, C18 as sum of Ys, E18 as sum of X*Y, and F18 as sum of squares.
To compute a, enter the followin formula in any cell (F35 for me):
F35=(E18-(B18*C18)/15)/(F18-(B18*B18)/15)
To compute b (in F36 for me):
F36=C18/15-F35*(B18/15)
Column D values, computing the trend line according to the y = ax + b:
D3=$F$35*B3+$F$36, D4=$F$35*B4+$F$36 and so on (until D17 for me).
Select the column datas (C2:D17) to make the graph.
HTH.
非常感谢您的解决方案,我正在挠头。
这是我在 Excel 中应用该解决方案的方法。
我在Excel中成功使用了MUHD给出的两个函数:
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 是 MUHD 解决方案中的 b 和 a)。
- 制作了 4 列,例如:
注意:我的值 y 值在 B3:B17 中,所以我有 n=15;
我的 x 值为 1,2,3,4...15。
1. B 列:已知 x
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 作为 Xs 的总和,C18 作为 Ys 的总和,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) 来制作图表。
哈。
回答by Thymine
Here is a very quick (and semi-dirty) implementation of Bedwyr Humphreys's answer. The interface should be compatible with @matt's answer as well, but uses decimal
instead of int
and uses more IEnumerable concepts to hopefully make it easier to use and read.
这是Bedwyr Humphreys 的答案的一个非常快速(和半脏)的实现。该界面也应该与@matt的答案兼容,但使用decimal
而不是int
使用更多 IEnumerable 概念,希望使其更易于使用和阅读。
Slope
is b
, Intercept
is a
Slope
是b
,Intercept
是a
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;
}
}
回答by Magn3144
This is the way i calculated the slope: Source: http://classroom.synonym.com/calculate-trendline-2709.html
这是我计算斜率的方式:来源: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;
}
回答by Todd Skelton
Here's what I ended up using.
这是我最终使用的。
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;
}
}
My data set is using a Unix timestamp for the x-axis and a decimal for the y. Change those datatypes to fit your need. I do all the sum calculations in one iteration for the best possible performance.
我的数据集对 x 轴使用 Unix 时间戳,对 y 使用小数。更改这些数据类型以满足您的需要。我在一次迭代中完成所有总和计算,以获得最佳性能。
回答by jonyB
If anyone needs the JS code for calculating the trendline of many points on a graph, here's what worked for us in the end:
如果有人需要 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
}
}
It takes an array of (x,y) points and returns the function of a y given a certain x Have fun :)
它需要一个 (x,y) 点数组,并返回给定某个 x 的 y 函数 玩得开心 :)