谷歌不是我的朋友 - 自从我在大学的统计课程已经很长时间了......我需要在图表上计算趋势线的起点和终点 - 是否有一种简单的方法可以做到这一点? (在C#中工作,但无论什么语言适合你)
答案 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 fitting或Least Squares Fitting - 非常简单但可行。如果你知道你喜欢什么样的拟合,你会在最小二乘拟合网页(指数,多项式等)的底部看到各种类型的曲线拟合。
此外,如果这是一次性的,请使用Excel。
答案 3 :(得分:15)
这是Bedwyr Humphreys's answer的一个非常快速(和半脏)的实现。该界面也应与@matt的答案兼容,但使用decimal
代替int
,并使用更多IEnumerable概念,以便更容易使用和阅读。
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;
}
}
答案 4 :(得分:3)
关于先前的答案
如果(B)y =偏移+斜率* x
然后(C)偏移= y /(斜率* x)错误
(C)应该是:
偏移= y-(斜率* x)
答案 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;
}
}