提问人:matt 提问时间:9/4/2008 最后编辑:Steven Vmatt 更新时间:5/31/2023 访问量:136904
如何计算图表的趋势线?
How do I calculate a trendline for a graph?
答:
好的,这是我最好的伪数学:
您的线路的方程式为:
Y = a + bX
哪里:
b = (sum(x*y) - sum(x)sum(y)/n) / (sum(x^2) - sum(x)^2/n)
a = 总和(y)/n - b(总和(x)/n)
其中 sum(xy) 是所有 x*y 等的总和。我承认不是特别清楚,但这是我在没有西格玛符号的情况下能做的最好的事情:)
...现在增加了 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。
评论
如果您有权访问 Excel,请查看“帮助”中“函数参考”的“统计函数”部分。对于直线最佳拟合,您需要 SLOPE 和 INTERCEPT,方程就在那里。
哦,等等,它们也在这里在线定义:http://office.microsoft.com/en-us/excel/HP052092641033.aspx SLOPE,还有一个指向 INTERCEPT 的链接。当然,这是假设MS不移动页面,在这种情况下,请尝试在谷歌上搜索“斜率截距方程Excel站点:微软.COM”之类的内容 - 刚才给出的链接是第三个。
感谢大家的帮助 - 我离开了这个问题几天,然后又回到了它 - 能够把它拼凑在一起 - 不是最优雅的代码,但它适用于我的目的 - 如果其他人遇到这个问题,我想我会分享:
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;
}
}
评论
xAxisVales.First()
.Last()
)
关于之前的答案
如果 (B) y = 偏移量 + 斜率*x
则 (C) 偏移量 = y/(斜率*x) 是错误的
(三)应当:
偏移量 = y-(斜率*x)
请参见:http://zedgraph.org/wiki/index.php?title=Trend
非常感谢你的解决方案,我挠了挠头。
以下是我在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) 以制作图形。
HTH。
这是 Bedwyr Humphreys 答案的一个非常快速(和半脏)的实现。该接口也应该与 @matt 的答案兼容,但使用而不是使用更多的 IEnumerable 概念,希望使其更易于使用和阅读。decimal
int
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;
}
}
这是我计算斜率的方法: 来源: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;
}
这是我最终使用的内容。
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 使用小数点。更改这些数据类型以满足您的需要。我在一次迭代中完成所有总和计算,以获得最佳性能。
如果有人需要 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 的函数 玩得开心:)
这是 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)
}
我将 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;
}
}
评论
除以 n 的效率不是很高。按如下方式重写公式
假设 Y = a + bX 是趋势线
n x,y 点数
然后
b = (nΣ(xy) - ΣxΣy) / (nΣ(x^2) - (Σx)^2) a = (Σy - bΣx)
/n
同 来源:http://classroom.synonym.com/calculate-trendline-2709.html
下一个:计算视频时长 [已关闭]
评论