51 votes

Comment calculer une ligne de tendance pour un graphique ?

Google n'est pas mon ami - cela fait longtemps que je n'ai pas suivi de cours de statistiques à l'université... Je dois calculer les points de départ et d'arrivée d'une ligne de tendance sur un graphique - existe-t-il un moyen simple de le faire ? (je travaille en C# mais n'importe quel langage vous convient)

0 votes

L'ajustement par les moindres carrés est votre meilleure chance.

36voto

matt Points 666

Merci à tous pour votre aide - j'ai été absent de ce problème pendant quelques jours et je viens d'y revenir - j'ai pu bricoler ceci - ce n'est pas le code le plus élégant, mais il fonctionne pour mes besoins - j'ai pensé partager si quelqu'un d'autre rencontre ce problème :

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

2 votes

Considérons la solution proposée par Bedwyr Humphreys

0 votes

Je pense que cela suppose que les données sont triées (en raison de l'utilisation de la fonction xAxisVales.First() et .Last() )

0 votes

La valeur de la pente doit être un double et non un nombre entier.

30voto

blank Points 7947

OK, voici mes meilleurs pseudo-maths :

L'équation de votre ligne est :

Y = a + bX

Où :

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

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

Où sum(xy) est la somme de tous les x*y, etc. Ce n'est pas très clair, je l'admets, mais c'est le mieux que je puisse faire sans le symbole sigma :)

... et maintenant avec un Sigma supplémentaire

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

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

Où Σ(xy) est la somme de tous les x*y, etc. et n est le nombre de points.

1 votes

Cela m'aiderait beaucoup si je pouvais trouver ce que n représente.

0 votes

Le cours de maths revient - n est le nombre de points sur un axe, non ?

1 votes

Dans votre équation pour b, quel est le deuxième signe = censé être ?

19voto

Adam Davis Points 47683

Étant donné que la ligne de tendance est droite, trouvez la pente en choisissant deux points quelconques et en les calculant :

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

Il faut ensuite trouver le décalage de la ligne. La ligne est spécifiée par l'équation :

(B) y = décalage + pente*x

Donc tu dois résoudre le décalage. Choisissez n'importe quel point de la ligne, et résolvez le décalage :

(C) décalage = y - (pente*x)

Vous pouvez maintenant insérer la pente et le décalage dans l'équation de la ligne (B) et obtenir l'équation qui définit votre ligne. Si votre ligne comporte du bruit, vous devrez choisir un algorithme de calcul de la moyenne ou utiliser une sorte d'ajustement de courbe.

Si votre ligne n'est pas droite, il vous faudra envisager de Ajustement des courbes ou Ajustement des moindres carrés - non trivial, mais faisable. Vous verrez les différents types d'ajustement de courbe au bas de la page Web de l'ajustement des moindres carrés (exponentiel, polynomial, etc.) si vous savez quel type d'ajustement vous souhaitez.

De même, s'il s'agit d'un cas unique, utilisez Excel.

32 votes

Je suis pratiquement certain que cela ne donnera pas une ligne de tendance ajustée ; la pente calculée en (A) sera sensiblement différente selon les "deux points" choisis. Il ne s'agit pas d'une ligne de tendance ajustée.

3 votes

1 votes

@Jay Ainsi la phrase, "Si votre ligne a du bruit, vous devrez décider d'un algorithme de moyenne ou utiliser une sorte d'ajustement de courbe."

18voto

Thymine Points 2198

Voici une mise en œuvre très rapide (et semi-salissante) de la fonction La réponse de Bedwyr Humphreys . L'interface doit être compatible avec @matt La réponse de l'entreprise est aussi la même, mais elle utilise decimal au lieu de int et utilise davantage de concepts IEnumerable afin d'espérer le rendre plus facile à utiliser et à lire.

Slope est b , Intercept est 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;
    }
}

3voto

Concernant une réponse précédente

si (B) y = décalage + pente*x

puis (C) décalage = y/(pente*x) c'est faux

(C) devrait être :

offset = y-(slope*x)

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X