Как мне рассчитать линию тренда для графика?

StackOverflow https://stackoverflow.com/questions/43224

  •  09-06-2019
  •  | 
  •  

Вопрос

Google мне не друг - прошло много времени с тех пор, как я изучал статистику в колледже...Мне нужно рассчитать начальную и конечную точки линии тренда на графике - есть ли простой способ сделать это?(работаете на C #, но любой язык подходит именно вам)

Это было полезно?

Решение

Учитывая, что линия тренда прямая, найдите наклон, выбрав любые две точки и рассчитав:

(A) наклон = (y1-y2)/(x1-x2)

Затем вам нужно найти смещение для линии.Линия задается уравнением:

(B) y = смещение + наклон *x

Итак, вам нужно решить проблему смещения.Выберите любую точку на линии и вычислите смещение:

(C) смещение = y - (наклон*x)

Теперь вы можете включить наклон и смещение в уравнение линии (B) и получить уравнение, определяющее вашу линию.Если в вашей линии есть шум, вам придется выбрать алгоритм усреднения или использовать какую-либо подгонку кривой.

Если ваша линия не прямая, то вам нужно будет изучить Подгонка кривой, или Подгонка по методу наименьших квадратов - нетривиально, но выполнимо.Вы увидите различные типы подгонки кривой в нижней части веб-страницы "Подгонка по методу наименьших квадратов" (экспоненциальная, полиномиальная и т.д.), Если знаете, какую подгонку вы хотели бы получить.

Кроме того, если это одноразовый метод, используйте Excel.

Другие советы

Спасибо всем за вашу помощь - я отключился от этой проблемы на пару дней и только что вернулся к ней - смог собрать это воедино - не самый элегантный код, но он работает для моих целей - подумал, что поделюсь, если кто-нибудь еще столкнется с этой проблемой:

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

Ладно, вот моя лучшая псевдоматематика:

Уравнение для вашей линии выглядит следующим образом:

Y = a + bX

Где:

b = (сумма(x*y) - сумма(x), сумма(y)/n) / (сумма(x^2) - сумма (x)^2/n)

a = сумма (y)/n - b(сумма(x)/n)

Где sum(xy) - это сумма всех x * y и т.д.Признаю, не совсем понятно, но это лучшее, что я могу сделать без символа сигмы :)

...и теперь с добавлением Сигмы

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

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

Где Σ (xy) - сумма всех x * y и т.д.а n - количество точек

Вот очень быстрая (и полу-грязная) реализация Ответ Бедуира Хамфриса.Интерфейс должен быть совместим с @мэттэто тоже ответ, но использует decimal вместо того, чтобы int и использует больше IEnumerable концепций, чтобы, как мы надеемся, упростить его использование и чтение.

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

Что касается предыдущего ответа

если (B) y = смещение + наклон *x

тогда (C) смещение = y/(наклон*x) это неправильно

(C) должно быть:

смещение = y-(наклон*x)

Видишь:http://zedgraph.org/wiki/index.php?title=Trend

Если у вас есть доступ к Excel, загляните в раздел "Статистические функции" справочника по функциям в справке.Для наилучшего соответствия прямой линии вам нужны НАКЛОН и ПЕРЕСЕЧЕНИЕ, и уравнения находятся прямо здесь.

О, подождите, они также определены онлайн здесь: http://office.microsoft.com/en-us/excel/HP052092641033.aspx для SLOPE, и там есть ссылка для ПЕРЕХВАТА.Конечно, это предполагает, что MS не перемещает страницу, и в этом случае попробуйте поискать в Google что-то вроде "УРАВНЕНИЕ ПЕРЕСЕЧЕНИЯ НАКЛОНА Excel site:microsoft.com" - приведенная ссылка только что стала третьей.

Вот как я рассчитал наклон:Источник: 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;
    }
}

Мой набор данных использует временную метку Unix для оси x и десятичную дробь для y.Измените эти типы данных в соответствии с вашими потребностями.Я выполняю все вычисления суммы за одну итерацию для достижения наилучшей возможной производительности.

Большое Вам спасибо за решение, я ломал голову.
Вот как я применил это решение в Excel.
Я успешно использовал две функции, предоставленные MUHD в Excel:
a = (сумма (x*y) - сумма (x), сумма(y)/n) / (сумма(x^2) - сумма (x)^2/n)
b = сумма (y)/n - b(сумма(x)/n)
(осторожно, мои a и b - это b и a в решении MUHD).

- Сделал 4 колонки, например:
Примечание:мои значения y находятся в B3: B17, так что у меня n = 15;
мои значения x равны 1,2,3,4 ... 15.
1.Колонка В:Известные x's
2.Колонка С:Известные y's
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), чтобы построить график.
ХТХ.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top