Como faço para calcular uma linha de tendência para um gráfico?

O Google não está sendo meu amigo – faz muito tempo desde a minha aula de estatística na faculdade … Preciso calcular os pontos inicial e final de uma linha de tendência em um gráfico – há uma maneira fácil de fazer isso? (trabalhando em C # mas qualquer que seja a linguagem que funcione para você)

Dado que a linha de tendência é reta, encontre a inclinação escolhendo dois pontos e calculando:

(A) declive = (y1-y2) / (x1-x2)

Então você precisa encontrar o deslocamento para a linha. A linha é especificada pela equação:

(B) y = offset + inclinação * x

Então você precisa resolver para compensar. Escolha qualquer ponto na linha e resolva o deslocamento:

(C) deslocamento = y – (inclinação * x)

Agora você pode conectar a inclinação e o deslocamento na equação de linha (B) e ter a equação que define sua linha. Se sua linha tiver ruído, você terá que decidir sobre um algoritmo de cálculo da média ou usar algum tipo de ajuste de curva.

Se sua linha não é reta, então você precisa olhar para Curve fitting , ou Least Squares Fitting – não trivial, mas capaz de fazer. Você verá os vários tipos de ajuste de curva na parte inferior da página da Web de ajuste de mínimos quadrados (exponencial, polinomial etc.) se você souber que tipo de ajuste deseja.

Além disso, se isso for único, use o Excel.

Obrigado a todos por sua ajuda – eu estava fora desta questão por um par de dias e só voltei a ele – foi capaz de remendar isso juntos – não o código mais elegante, mas funciona para os meus propósitos – pensei que eu compartilharia se qualquer outra pessoa encontra esse problema:

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; } } 

OK, aqui está a minha melhor pseudo matemática:

A equação da sua linha é:

Y = a + bx

Onde:

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

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

Onde sum (xy) é a sum de todos os x * y etc. Não é particularmente claro que eu concedo, mas é o melhor que posso fazer sem um símbolo sigma 🙂

… e agora com o Sigma adicionado

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

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

Onde Σ (xy) é a sum de todos os x * y etc. e n é o número de pontos

Aqui está uma implementação muito rápida (e semi-suja) da resposta de Bedwyr Humphreys . A interface também deve ser compatível com a resposta da @matt , mas usa decimal vez de int e usa mais conceitos IEnumerable para facilitar o uso e a leitura.

Slope é b , Intercept é a

 public class Trendline { public Trendline(IList yAxisValues, 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; } } 

Em relação a uma resposta anterior

if (B) y = deslocamento + inclinação * x

então (C) offset = y / (slope * x) está errado

(C) deve ser:

deslocamento = y- (inclinação * x)

Veja: http://zedgraph.org/wiki/index.php?title=Trend

Se você tiver access ao Excel, consulte a seção “Funções statistics” da Referência de function na Ajuda. Para o melhor ajuste em linha reta, você precisa de SLOPE e INTERCEPT e as equações estão logo ali.

Ah, aguarde, eles também estão definidos on-line aqui: http://office.microsoft.com/en-us/excel/HP052092641033.aspx para SLOPE, e há um link para o INTERCEPT. Naturalmente, isso pressupõe que o MS não mova a página. Nesse caso, pesquise por algo como “SLOPE INTERCEPT EQUATION Excel site: microsoft.com” – o link fornecido acabou sendo o terceiro agora.

Muito obrigado pela solução, eu estava coçando a cabeça.
Aqui está como eu apliquei a solução no Excel.
Eu usei com sucesso as duas funções dadas pelo MUHD no 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)
(cuidado meu a e b são o b e um na solução de MUHD).

– Feito 4 colunas, por exemplo:
NB: meus valores y estão em B3: B17, então eu tenho n = 15;
meus valores x são 1,2,3,4 … 15.
1. Coluna B: x conhecido
2. Coluna C: Ys Conhecidos
3. Coluna D: A linha de tendência computada
4. Valores da coluna E: B * Valores C (E3 = B3 * C3, E4 = B4 * C4, …, E17 = B17 * C17)
5. Coluna F: valores x ao quadrado
Eu então somo as colunas B, C e E, as sums vão na linha 18 para mim, então eu tenho B18 como sum de Xs, C18 como sum de Ys, E18 como sum de X * Y e F18 como sum de quadrados.
Para calcular a, insira a seguinte fórmula em qualquer célula (F35 para mim):
F35 = (E18- (B18 * C18) / 15) / (F18- (B18 * B18) / 15)
Para calcular b (em F36 para mim):
F36 = C18 / 15-F35 * (B18 / 15)
Valores da coluna D, calculando a linha de tendência de acordo com y = ax + b:
D3 = $ F $ 35 * B3 + $ F $ 36, D4 = $ F $ 35 * B4 + $ F $ 36 e assim por diante (até o D17 para mim).

Selecione os dados da coluna (C2: D17) para fazer o gráfico.
HTH.

Esta é a maneira que eu calculei a inclinação: Fonte: http://classroom.synonym.com/calculate-trendline-2709.html

 class Program { public double CalculateTrendlineSlope(List 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; } 

Aqui está o que acabei usando.

 public class DataPoint { 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> 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; } } 

Meu dataset está usando um carimbo de data / hora Unix para o eixo x e um decimal para o y. Altere esses tipos de dados para atender à sua necessidade. Eu faço todos os cálculos de sum em uma iteração para o melhor desempenho possível.