Pregunta

Google no está siendo mi amigo; ha pasado mucho tiempo desde mi clase de estadística en la universidad... Necesito calcular los puntos inicial y final de una línea de tendencia en un gráfico. ¿Existe una manera fácil de hacerlo?(trabajando en C# pero cualquier lenguaje que funcione para usted)

¿Fue útil?

Solución

Dado que la línea de tendencia es recta, encuentre la pendiente eligiendo dos puntos cualesquiera y calculando:

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

Entonces necesitas encontrar el desplazamiento de la línea.La línea está especificada por la ecuación:

(B) y = desplazamiento + pendiente*x

Entonces necesitas resolver el desplazamiento.Elija cualquier punto de la línea y resuelva el desplazamiento:

(C) desplazamiento = y - (pendiente*x)

Ahora puedes introducir la pendiente y el desplazamiento en la ecuación de la línea (B) y tener la ecuación que define tu línea.Si su línea tiene ruido, tendrá que decidir sobre un algoritmo de promedio o utilizar algún tipo de ajuste de curva.

Si tu línea no es recta, tendrás que investigar Ajuste de curvas, o Ajuste de mínimos cuadrados - no trivial, pero factible.Verá los distintos tipos de ajuste de curvas en la parte inferior de la página web de ajuste de mínimos cuadrados (exponencial, polinómico, etc.) si sabe qué tipo de ajuste le gustaría.

Además, si se trata de algo puntual, utilice Excel.

Otros consejos

Gracias a todos por su ayuda. Estuve fuera de este problema durante un par de días y acabo de volver a él. Pude improvisar esto. No es el código más elegante, pero funciona para mis propósitos. Pensé en compartirlo si alguien más encuentra este 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;
    }
}

Bien, aquí está mi mejor pseudomatemática:

La ecuación de tu recta es:

Y = a + bX

Dónde:

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

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

Donde suma(xy) es la suma de todos x*y, etc.No es particularmente claro, lo admito, pero es lo mejor que puedo hacer sin un símbolo sigma :)

...y ahora con Sigma agregado

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

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

Donde Σ(xy) es la suma de todos x*y, etc.y n es el número de puntos

Aquí hay una implementación muy rápida (y semi-sucia) de La respuesta de Bedwyr Humphreys.La interfaz debe ser compatible con @mateLa respuesta también, pero usa. decimal en lugar de int y utiliza más conceptos IEnumerable para, con suerte, hacerlo más fácil de usar y leer.

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

Respecto a una respuesta anterior

si (B) y = desplazamiento + pendiente*x

entonces (C) desplazamiento = y/(pendiente*x) Está Mal

(C) debería ser:

desplazamiento = y-(pendiente*x)

Ver:http://zedgraph.org/wiki/index.php?title=Tendencia

Si tiene acceso a Excel, busque en la sección "Funciones estadísticas" de la Referencia de funciones en la Ayuda.Para obtener el mejor ajuste en línea recta, necesita PENDIENTE e INTERCEPCIÓN y las ecuaciones están ahí.

Oh, espera, también están definidos en línea aquí: http://office.microsoft.com/en-us/excel/HP052092641033.aspx para SLOPE, y hay un enlace a INTERCEPT.Por supuesto, eso supone que MS no mueve la página, en cuyo caso intente buscar en Google algo como "ESCUACIÓN DE INTERCEPCIÓN DE PENDIENTE Sitio de Excel: microsoft.com"; el enlace proporcionado resultó ser el tercero hace un momento.

Así es como calculé la pendiente:Fuente: 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;
    }

Esto es lo que terminé 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;
    }
}

Mi conjunto de datos utiliza una marca de tiempo Unix para el eje x y un decimal para el eje y.Cambie esos tipos de datos para que se ajusten a sus necesidades.Hago todos los cálculos de suma en una iteración para obtener el mejor rendimiento posible.

Muchas gracias por la solución, me estaba rascando la cabeza.
Así es como apliqué la solución en Excel.
Utilicé con éxito las dos funciones proporcionadas por MUHD en Excel:
a = (suma(x*y) - suma(x)suma(y)/n) / (suma(x^2) - suma(x)^2/n)
b = suma(y)/n - b(suma(x)/n)
(cuidado, mis a y b son b y a en la solución de MUHD).

- Hizo 4 columnas, por ejemplo:
NÓTESE BIEN:mis valores y valores están en B3:B17, entonces tengo n=15;
mis valores de x son 1,2,3,4...15.
1.Columna B:x conocidas
2.Columna C:Y conocidos
3.Columna D:La línea de tendencia calculada
4.Columna E:Valores B * Valores C (E3=B3*C3, E4=B4*C4, ..., E17=B17*C17)
5.Columna F:valores x al cuadrado
Luego sumo las columnas B, C y E, las sumas van en la línea 18 para mí, así que tengo B18 como suma de X, C18 como suma de Y, E18 como suma de X*Y y F18 como suma de cuadrados.
Para calcular a, ingrese la siguiente fórmula en cualquier celda (F35 para mí):
F35=(E18-(B18*C18)/15)/(F18-(B18*B18)/15)
Para calcular b (en F36 para mí):
F36=C18/15-F35*(B18/15)
Valores de la columna D, calculando la línea de tendencia según y = ax + b:
D3=$F$35*B3+$F$36, D4=$F$35*B4+$F$36 y así sucesivamente (hasta D17 para mí).

Seleccione los datos de la columna (C2:D17) para hacer el gráfico.
HTH.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top