Question

Google n'est pas mon ami - cela fait longtemps depuis mon cours de statistiques à l'université... Je dois calculer les points de début et de fin d'une ligne de tendance sur un graphique - existe-t-il un moyen simple de le faire ?(travailler en C# mais quel que soit le langage qui vous convient)

Était-ce utile?

La solution

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

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

Ensuite, vous devez trouver le décalage de la ligne.La droite est spécifiée par l'équation :

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

Vous devez donc résoudre le décalage.Choisissez n'importe quel point sur la ligne et résolvez le décalage :

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

Vous pouvez maintenant intégrer 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 présente du bruit, vous devrez choisir un algorithme de moyenne ou utiliser un ajustement de courbe.

Si votre ligne n'est pas droite, vous devrez vérifier Courbe d'ajustement, 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 d'ajustement des moindres carrés (exponentielle, polynomiale, etc.) si vous savez quel type d'ajustement vous souhaitez.

De plus, s’il s’agit d’un cas ponctuel, utilisez Excel.

Autres conseils

Merci à tous pour votre aide - j'ai été absent sur ce problème pendant quelques jours et j'y suis juste revenu - j'ai pu bricoler cela - pas le code le plus élégant, mais cela fonctionne pour mes besoins - j'ai pensé que je partagerais 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;
    }
}

OK, voici mon meilleur pseudo calcul :

L'équation de votre droite 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 x*y etc.Pas particulièrement clair je l'avoue, mais c'est le mieux que je puisse faire sans symbole sigma :)

...et maintenant avec Sigma ajouté

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

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

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

Voici une implémentation très rapide (et semi-sale) de Réponse de Bedwyr Humphreys.L'interface doit être compatible avec @matLa réponse de est également, mais utilise decimal au lieu de int et utilise davantage de concepts IEnumerable pour, espérons-le, 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;
    }
}

Concernant une réponse précédente

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

alors (C) décalage = y/(pente*x) est faux

(C) devrait être :

décalage = y-(pente*x)

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

Si vous avez accès à Excel, consultez la section « Fonctions statistiques » de la référence des fonctions dans l'aide.Pour un meilleur ajustement en ligne droite, vous avez besoin de PENTE et d'INTERCEPTION et les équations sont là.

Oh, attendez, ils sont également définis en ligne ici : http://office.microsoft.com/en-us/excel/HP052092641033.aspx pour SLOPE, et il y a un lien vers INTERCEPT.BIEN sûr, cela suppose que MS ne déplace pas la page, auquel cas essayez de rechercher sur Google quelque chose comme "Site Excel d'ÉQUATION D'INTERCEPT DE PENTE: microsoft.com" - le lien donné s'est avéré troisième à l'instant.

Voici comment j'ai calculé la pente :Source: 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;
    }

Voici ce que j'ai fini par utiliser.

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

Mon ensemble de données utilise un horodatage Unix pour l'axe des x et un nombre décimal pour le y.Modifiez ces types de données en fonction de vos besoins.Je fais tous les calculs de somme en une seule itération pour les meilleures performances possibles.

Merci beaucoup pour la solution, je me grattais la tête.
Voici comment j'ai appliqué la solution dans Excel.
J'ai utilisé avec succès les deux fonctions fournies par MUHD dans Excel :
a = (somme(x*y) - somme(x)somme(y)/n) / (somme(x^2) - somme(x)^2/n)
b = somme(y)/n - b(somme(x)/n)
(attention, mes a et b sont les b et a dans la solution de MUHD).

- Fait 4 colonnes, par exemple :
Attention :mes valeurs y sont dans B3:B17, j'ai donc n=15 ;
mes valeurs x sont 1,2,3,4...15.
1.Colonne B :X connus
2.Colonne C :Je connais les Y.
3.Colonne D :La ligne de tendance calculée
4.Colonne E :Valeurs B * valeurs C (E3=B3*C3, E4=B4*C4, ..., E17=B17*C17)
5.Colonne F :x valeurs au carré
Je additionne ensuite les colonnes B, C et E, les sommes vont à la ligne 18 pour moi, j'ai donc B18 comme somme de X, C18 comme somme de Y, E18 comme somme de X*Y et F18 comme somme de carrés.
Pour calculer a, entrez la formule suivante dans n'importe quelle cellule (F35 pour moi) :
F35=(E18-(B18*C18)/15)/(F18-(B18*B18)/15)
Pour calculer b (en F36 pour moi) :
F36=C18/15-F35*(B18/15)
Valeurs de la colonne D, calculant la ligne de tendance selon y = ax + b :
D3=$F$35*B3+$F$36, D4=$F$35*B4+$F$36 et ainsi de suite (jusqu'à D17 pour moi).

Sélectionnez les données de la colonne (C2:D17) pour créer le graphique.
HTH.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top