Pergunta

O Google não está sendo meu amigo - tem sido um longo tempo desde o meu estatísticas de classe na faculdade...eu preciso calcular os pontos de início e fim para uma linha de tendência num gráfico, há uma maneira fácil de fazer isso?(trabalho em C#, mas qualquer que seja a linguagem funciona para você)

Foi útil?

Solução

Dado que a linha de tendência é reto, encontrar a inclinação escolhendo dois pontos quaisquer e cálculo:

(A) inclinação = (y1-y2)/(x1-x2)

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

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

Portanto, você precisa para resolver a compensar.Escolha qualquer ponto da linha, e resolver a compensar:

(C) compensação = y - (inclinação*x)

Agora você pode encaixe inclinação e deslocamento para a equação da linha (B) e tem a equação que define a sua linha.Se a linha tem ruído que você terá que decidir sobre uma média de algoritmo, ou utilizar o ajuste da curva de algum tipo.

Se a linha não é reta, em seguida, você vai precisar de olhar para O ajuste da curva, ou Mínimos Quadrados De Encaixe - não trivial, mas capaz de fazer.Você vai ver os vários tipos de ajuste de curva na parte inferior dos mínimos quadrados montagem de página web (exponencial, polinomial, etc) se você sabe que tipo de ajuste que você gostaria.

Também, se este é um one-off, use o Excel.

Outras dicas

Obrigado a todos por sua ajuda - eu estava fora esse problema para um par de dias e acabei de voltar para ele, foi capaz de calçada isso juntos - não o mais elegante código, mas funciona para os meus fins - pensei que eu iria partilhar se alguém encontrar esse problema:

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

OK, aqui é meu melhor pseudo matemática:

A equação para a sua linha é:

Y = a + bX

Onde:

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

a = soma(y)/n - b(sum(x)/n)

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

...e agora, com adição de Sigma

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

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

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

Aqui está um rápido (e semi-suja) implementação de Bedwyr Humphreys resposta.A interface deve ser compatível com @matt's respostas bem, mas usa decimal em vez de int e usa mais IEnumerable conceitos com a esperança de tornar mais fácil a utilização e leia.

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

A respeito de uma resposta anterior

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

em seguida, (C) compensação = y/(inclinação*x) é errado

(C) deve ser:

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

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

Se você tiver o access para o Excel, procure na seção "Funções de Estatística" seção de Referência de Função dentro de Ajudar.Para a linha reta de melhor ajuste, você precisa de INCLINAÇÃO e o INTERCEPTO e as equações estão ali.

Oh, espere, eles também são definidos on-line aqui: http://office.microsoft.com/en-us/excel/HP052092641033.aspx para INCLINAÇÃO, e há um link para INTERCEPTAR.É claro, que assume a MS não mover a página, no caso, tente usar o google algo como "SLOPE INTERCEPT EQUAÇÃO Excel site:microsoft.com" - o link dada acabou em terceiro, mesmo agora.

Esta é a maneira que eu calculado o declive:Fonte: 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;
    }

Aqui está o que eu acabei usando.

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

Meu conjunto de dados é usando um Unix timestamp para o eixo x e uma casa decimal para a y.Altere os tipos de dados para atender à sua necessidade.Eu faço toda a soma de seus cálculos em uma iteração para o melhor desempenho possível.

Muito obrigado para a solução, eu estava coçando minha cabeça.
Aqui está como eu aplicada a solução no Excel.
Eu utilizados com sucesso as duas funções dadas por MUHD no Excel:
a = (soma(x*y) - sum(x)sum(y)/n) / (sum(x^2) - sum(x)^2/n)
b = sum(y)/n - b(sum(x)/n)
(cuidado meu b-a b e um na MUHD da solução).

- Fiz 4 colunas, por exemplo:
NB:meus valores valores de y estão em B3:B17, então eu tenho n=15;
minha valores de x são 1,2,3,4...15.
1.Coluna B:Conhecido x
2.Coluna C:Y conhecidos
3.Coluna D:A linha de tendência calculada
4.Coluna E:Os valores de B * valores de C (E3=B3*C3, E4=B4*C4, ..., E17=B17*C17)
5.Coluna F:x ao quadrado os valores de
Eu, em seguida, some as colunas B,C e e, as somas ir na linha 18 para mim, então eu tenho B18 como a soma de Xs, C18 como a soma de Ys, E18 como a soma de X*Y, e F18 como a soma de quadrados.
Para calcular a, introduza a seguinte fórmula em qualquer célula (F35 para mim):
F35=(E18-(B18*C18)/15)/(F18-(B18*B18)/15)
Para calcular b (F36 para mim):
F36=C18/15-F35*(B18/15)
Coluna D valores, computando-se a linha de tendência de acordo com o y = ax + b:
D3=$F$35*B3+$F$36, D4=$F$35*B4+$F$36 e assim por diante (até D17 para mim).

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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top