Ayuda para escribir una regresión lineal - página 5

 
Rosh писал (а) >>

Y esto es lo que da Excel 2007



Por lo tanto, podría ser necesario comprobar Matcad.

Si he entendido bien, Excel da el tercer resultado, diferente de los dos primeros). ¿Dónde está la verdad? B es el mismo que Matcad, pero el coeficiente A es diferente.

 
Prival писал (а) >>

Si he entendido bien, Excel dio el tercer resultado, diferente de los dos primeros). ¿Dónde está la verdad? B es el mismo que en Matcad, pero el coeficiente A es diferente.

En general, con tantos dígitos significativos y un rango de cálculos tan amplio se va a la parte posterior de la mantisa. Es decir, incluso se pueden introducir elementos de aleatoriedad en la respuesta. Creo que la corrección sólo puede esperarse para algún algoritmo especial de alta precisión. En este caso, es mejor desplazar el origen de las coordenadas más cerca del rango X .



P.D. Especialmente cuando se calcula la suma de X*X, la información se va directamente al retrete :)

 
lna01 писал (а) >>

Generalmente, con tantos dígitos significativos y tal rango, los cálculos van en algún lugar de la parte posterior de la mantisa. Es decir, incluso se pueden introducir elementos de aleatoriedad en la respuesta. Creo que sólo se puede contar con la corrección para algún algoritmo especial con mayor precisión. Pero en este caso es mejor para mover el origen de coordenadas más cerca del rango X.

La cuestión es que he empezado a preparar el campeonato. Empecé a traducir mis desarrollos en Matkadec a MQL. Si recuerdas, estábamos construyendo la ACF (función de autocorrelación) y empecé con ella y decidí usar fórmulas directas, ya que ponía demasiada carga en la CPU a través de las transformadas de Fourier.

Por eso me puse a buscar el origen del rastrillo (

Intentaré desplazar X (Tiempo) a 0. Pero tendré que volver a revisar todo de nuevo. Ya tengo que renunciar al 50% de mis ideas.

 
Prival писал (а) >>

El caso es que he empezado a preparar el campeonato. Y empecé a transferir mis desarrollos en Matcadet a MQL. Si recuerdas, estábamos construyendo la ACF (función de autocorrelación), empecé con ella y decidí calcularla usando fórmulas directas, ya que las transformadas de Fourier son una carga pesada para el procesador.

Por eso me puse a buscar el origen del rastrillo (

Intentaré desplazar X (Tiempo) a 0. Pero tendré que volver a revisar todo de nuevo. Tal y como están las cosas, ya tengo que renunciar al 50% de mis ideas

MT mantiene 15 dígitos en la mantisa. Si extraemos la raíz obtenemos 10^7. Es decir, hay que elevar al cuadrado y sumar números mayores que 10000000, ver postdata del post anterior :). Afortunadamente, ese límite se corresponde con el número de barras de minutos en el historial real, por lo que si lo es, debería seguir funcionando. Pero si se trata del tiempo, entonces es inevitable un cambio de origen de coordenadas.


P.D. Por cierto, si vas a utilizar tu función en el campeonato, añade protección contra la división por cero. De lo contrario, existe el riesgo de que su indicador se quede parado en medio del campeonato. O al principio. Recuerden que hubo algo así con Fourier.

 

El mismo algoritmo en Java

import java.util.ArrayList;

public class Prival {
public static void main(String arg[]){
int N = 6;
double Y[];
double X[];
ArrayList<Double> Parameters = new ArrayList<Double>();
Parameters.add(0.0);
Parameters.add(0.0);
X = new double[6];
Y = new double[6];
for ( int i = 0; i < N; i ++ )
{
// массивы Y и X для проверки работоспособности
// intercept = -3.33333333 slope = 5.00000000

X[i]=i;
Y[i]=i*i;
}

LinearRegr(X, Y, N,Parameters);
System.out.println("intercept = "+Parameters.get(0)+" slope = "+ Parameters.get(1));

// вторая проверка
X[0]=1216640160;
X[1]=1216640100;
X[2]=1216640040;
X[3]=1216639980;
X[4]=1216639920;
X[5]=1216639860;

Y[0]=1.9971;
Y[1]=1.9970;
Y[2]=1.9967;
Y[3]=1.9969;
Y[4]=1.9968;
Y[5]=1.9968;


LinearRegr(X, Y, N, Parameters);
System.out.println("intercept = "+Parameters.get(0)+" slope = "+ Parameters.get(1));

}
public static void LinearRegr(double X[], double Y[], int N, ArrayList<Double> Parameters){
double sumY = 0.0, sumX = 0.0, sumXY = 0.0, sumX2 = 0.0;
double A=0,B=0;
for ( int i = 0; i < N; i ++ ){
sumY +=Y[i];
sumXY +=X[i]*Y[i];
sumX +=X[i];
sumX2 +=X[i]*X[i];
}
B=(sumXY*N-sumX*sumY)/(sumX2*N-sumX*sumX);
A=(sumY-sumX*B)/N;
Parameters.set(0, A);
Parameters.set(1, B);
}
}


Resultado:


intercepción = -3,33333333333335 pendiente = 5,0
intercepción = -1102,169141076954 pendiente = 9,075536028198574E-7

El proceso terminó con el código de salida 0

 

Rosh

Estoy de acuerdo en que estas fórmulas darán el mismo resultado aquí está matcad

Veo que los resultados coinciden con MQL y Java, pero matcad nunca me ha fallado, así que tengo dudas. Lo he comprobado y he ordenado los resultados.

Lo he comprobado y ordenado por X y he vuelto a calcular los coeficientes.

El resultado ha cambiado, esto no debería ser así. Lo más probable es que el error se deba a la acumulación de errores debido a la elevación al cuadrado de números grandes(el candidato tiene razón). Investigué la literatura y encontré una fórmula más sencilla, sin cuadrar y aparentemente con menos cálculos.

El resultado es el mismo que en matcad, y no depende de la ordenación.

Recomiendo utilizar esta fórmula para calcular los coeficientes de regresión lineal.

//+------------------------------------------------------------------+
//|                                                       LinReg.mq4 |
//|                                                    Привалов С.В. |
//|                                             Skype -> privalov-sv |
//+------------------------------------------------------------------+
#property copyright "Привалов С.В."
#property link      "Skype -> privalov-sv"

//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
   int      N=6;                 // Размер массива
   double   Y[],X[],A=0.0, B=0.0;
   
  ArrayResize(X,N);
  ArrayResize(Y,N);
      
// проверка 
    X[0]=1216640160;
    X[1]=1216640100;
    X[2]=1216640040;
    X[3]=1216639980;
    X[4]=1216639920;
    X[5]=1216639860;
    
    Y[0]=1.9971;
    Y[1]=1.9970;    
    Y[2]=1.9967;
    Y[3]=1.9969;    
    Y[4]=1.9968;    
    Y[5]=1.9968;
    
    
  LinearRegr(X, Y, N, A, B);
  
  Print("A = ", DoubleToStr(A,8)," B = ",DoubleToStr(B,8));
           
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Рассчет коэффициентов A и B в уравнении                          |
//| y(x)=A*x+B                                                       |
//| используються формулы https://forum.mql4.com/ru/10780/page5       |
//+------------------------------------------------------------------+

void LinearRegr(double X[], double Y[], int N, double& A, double& B)
{
      double mo_X = 0.0, mo_Y = 0.0, var_0 = 0.0, var_1 = 0.0;
      
    for ( int i = 0; i < N; i ++ )
      {
        mo_X +=X[i];
        mo_Y +=Y[i];
      }
    mo_X /=N;
    mo_Y /=N;
        
    for ( i = 0; i < N; i ++ )
      {
        var_0 +=(X[i]-mo_X)*(Y[i]-mo_Y);
        var_1 +=(X[i]-mo_X)*(X[i]-mo_X);
      }
        A = var_0 / var_1;
        B = mo_Y - A * mo_X;
}

Adjunto el script, si alguien limpia LinearRegr (para evitar errores al trabajar con datos reales y aumentar el rendimiento), será bueno. He intercambiado A y B, porque

La notación y(x)=a*x+b es más familiar (para mí por los libros).

Archivos adjuntos:
linreg_1.mq4  2 kb
 

No veo cómo el resultado puede depender de la clasificación. La ordenación no se utiliza explícitamente en ninguna parte de las fórmulas.


Además, este último algoritmo utiliza valores de expectativa de X e Y y potencialmente también puede introducir un error en los cálculos. Y otra cosa: usar dos bucles contra uno es poco probable que mejore el rendimiento.


Si necesitamos realizar cálculos masivos de regresión lineal sobre un número de secuencias de precios, es mejor seleccionar topes separados en un indicador y calcular usando el método del total acumulado. Permite acelerar los cálculos en órdenes de magnitud. Ejemplo - Kaufman AMA optimizado : Perry Kaufman AMA optimizado

 
Rosh писал (а) >>

No veo cómo el resultado puede depender de la clasificación. La ordenación no se utiliza explícitamente en ninguna parte de las fórmulas.


Además, el último algoritmo utiliza la expectativa de los valores X e Y, y potencialmente también puede introducir algún error en los cálculos. Una cosa más: utilizar dos bucles frente a uno apenas mejoraría el rendimiento.

Si necesitamos hacer los cálculos masivos de la regresión lineal para un número de secuencias de precios, es mejor seleccionar topes separados en un indicador y utilizar el método de totalización acumulativa. Permite acelerar los cálculos en órdenes de magnitud. Ejemplo - Kaufman AMA optimizado : Perry Kaufman AMA optimizado

1. La cuestión es que el resultado no debe depender de la ordenación, mientras que el algoritmo sí. Compruébalo.

//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
//----
   int      N=6;                 // Размер массива
   double   Y[],X[],Y1[],X1[],A=0.0, B=0.0;
   
  ArrayResize(X,N);
  ArrayResize(Y,N);
  ArrayResize(X1,N);
  ArrayResize(Y1,N);
      
// проверка 
    X[0]=1216640160;
    X[1]=1216640100;
    X[2]=1216640040;
    X[3]=1216639980;
    X[4]=1216639920;
    X[5]=1216639860;
    
    Y[0]=1.9971;
    Y[1]=1.9970;    
    Y[2]=1.9967;
    Y[3]=1.9969;    
    Y[4]=1.9968;    
    Y[5]=1.9968;
    

// отсортируем массив по возрастанию X (исходный массив был по убыванию)
  for (int i = 0; i < N; i++)
   {
   X1[i]=X[N-i-1];
   Y1[i]=Y[N-i-1];
//   Print(X[i], " ", X1[i], " ", Y[i], " ", Y1[i]);
   }            
//----
// 
  LinearRegr(X, Y, N, A, B);
  Print("A = ", DoubleToStr(A,8)," B = ",DoubleToStr(B,8));
  LinearRegr(X1, Y1, N, A, B);
  Print(" A = ", DoubleToStr(A,8)," B = ",DoubleToStr(B,8));

  LinearRegr1(X, Y, N, A, B);
  Print("A = ", DoubleToStr(A,8)," B = ",DoubleToStr(B,8));
  LinearRegr1(X1, Y1, N, A, B);
  Print(" A = ", DoubleToStr(A,8)," B = ",DoubleToStr(B,8));

   return(0);
  }

//-------------------------------------------------------------------------------
// использование этой формулы приводит к ошибкам если X=Time
// формула предложена вот тут https://forum.mql4.com/ru/10780/page4
//| y(x)=A+B*x  

void LinearRegr(double X[], double Y[], int N, double& A, double& B)
{
      double sumY = 0.0, sumX = 0.0, sumXY = 0.0, sumX2 = 0.0;
      
    for ( int i = 0; i < N; i ++ )
    {
        sumY   +=Y[i];
        sumXY  +=X[i]*Y[i];
        sumX   +=X[i];
        sumX2  +=X[i]*X[i];
    }
   B=(sumXY*N-sumX*sumY)/(sumX2*N-sumX*sumX);
   A=(sumY-sumX*B)/N;
}

//+------------------------------------------------------------------+
//| Формула предлагаемая мной                                        |
//| Рассчет коэффициентов A и B в уравнении                          |
//| y(x)=A*x+B                                                       |
//| используються формулы https://forum.mql4.com/ru/10780/page5       |
//+------------------------------------------------------------------+

void LinearRegr1(double X[], double Y[], int N, double& A, double& B)
{
      double mo_X = 0.0, mo_Y = 0.0, var_0 = 0.0, var_1 = 0.0;
      
    for ( int i = 0; i < N; i ++ )
      {
        mo_X +=X[i];
        mo_Y +=Y[i];
      }
    mo_X /=N;
    mo_Y /=N;
        
    for ( i = 0; i < N; i ++ )
      {
        var_0 +=(X[i]-mo_X)*(Y[i]-mo_Y);
        var_1 +=(X[i]-mo_X)*(X[i]-mo_X);
      }
        A = var_0 / var_1;
        B = mo_Y - A * mo_X;
}

El resultado es

2008.07.30 13:51:08 LinReg EURUSD,M1: A = 0.00000090 B = -1098.77264952

2008.07.30 13:51:08 LinReg EURUSD,M1: A = 0.00000090 B = -1098.77264952

2008.07.30 13:51:08 LinReg EURUSD,M1: A = -1078.77267965 B = 0.00000089

2008.07.30 13:51:08 LinReg EURUSD,M1: A = -1102.16914108 B = 0.00000091

Este no debería ser el caso.

Veo que aparecen dos bucles, por eso pedí un rendimiento más rápido. El algoritmo 'Regresión: ¿qué es?' puede ser más rápido, pero también deberíamos optimizarlo (creo que Vinin ya lo ha hecho).

3. Gracias por Kaufmann, es un buen indicador. Por si no lo has olvidado antes del segundo campeonato estuve captando inexactitudes en él. Gracias por corregirlos.

Z.U. Me gustaría preguntar a los que tienenMatlab. Introduce estas matrices y calcula las fórmulas incorporadas (que yo recuerde, las hay), y publica el resultado aquí. Para llegar a un consenso. Gracias. Ayuda )). Rosh es bastante difícil de convencer, pero yo también tengo una frente militar )))

 
Prival писал (а) >>

2. Veo que aparecen dos bucles, por eso pedí una aceleración. El algoritmo 'Regresión: ¿qué es?' puede ser más rápido, pero deberíamos optimizarlo también (creo que Vinin ya lo ha hecho).

Efectivamente, LWMA es más seguro que X*X, por lo que su trabajo con Mathemat adquiere un nuevo significado :). Pero sigo considerando mi primera recomendación (desplazar el origen de las coordenadas) como la mejor opción. ¿La sustitución formal de Time[pos] por Time[pos]-Time[Bars-1] en todas partes es un riesgo de error?

 
Prival писал (а) >>

1. Esa es la cuestión: el resultado no debería depender de la ordenación, pero en ese algoritmo sí. Compruébalo.

Resultado

2008.07.30 13:51:08 LinReg EURUSD,M1: A = 0.00000090 B = -1098.77264952

2008.07.30 13:51:08 LinReg EURUSD,M1: A = 0.00000090 B = -1098.77264952

2008.07.30 13:51:08 LinReg EURUSD,M1: A = -1078.77267965 B = 0.00000089

2008.07.30 13:51:08 LinReg EURUSD,M1: A = -1102.16914108 B = 0.00000091

Este no debería ser el caso.



Inserte el ristrintokwa en su código:

//-------------------------------------------------------------------------------
// использование этой формулы приводит к ошибкам если X=Time
// формула предложена вот тут https://forum.mql4.com/ru/10780/page4
//| y(x)=A+B*x  
 
void LinearRegr(double X[], double Y[], int N, double& A, double& B)
{
      double sumY = 0.0, sumX = 0.0, sumXY = 0.0, sumX2 = 0.0;
      
    for ( int i = 0; i < N; i ++ )
    {
        sumY   +=Y[i];
        sumXY  +=X[i]*Y[i];
        sumX   +=X[i];
        sumX2  +=X[i]*X[i];
    }
   Print("sumY = ",DoubleToStr(sumY,8)," sumX = ",DoubleToStr(sumX,8)," sumXY = ",DoubleToStr(sumXY,8)," sumX2 = ",DoubleToStr(sumX2,8));
   Print("sumXY*dN-sumX*sumY = ",DoubleToStr(sumXY*dN-sumX*sumY,8));    
   Print("sumX2*dN-sumX*sumX = ",DoubleToStr(sumX2*dN-sumX*sumX,8));    
 
   B=(sumXY*N-sumX*sumY)/(sumX2*N-sumX*sumX);
   A=(sumY-sumX*B)/N;
}

Consigue algo como esto:

primera llamada
sumY = 11.98130000 sumX = 7299840060.00000000 sumXY = 14576928951.87000100 sumX2 = 8881277483596863500.00000000
sumaXY*dN-sumaX*sumaY = 0,34199524
sumaX2*dN-sumaX*sumaX = 376832.00000000
A = -1102,16914108 B = 0,00000091
segunda llamada
sumY = 11.98130000 sumX = 7299840060.00000000 sumXY = 14576928951.87000300 sumX2 = 8881277483596864500.00000000
sumaXY*dN-sumaX*sumaY = 0,34202576
sumaX2*dN-sumaX*sumaX = 385024.00000000
A = -1078,77267965 B = 0,00000089

Este es otro escollo de los cálculos informáticos y del redondeo. Por un lado, yo mismo no me esperaba un rastrillo así, pero por otro lado es comprensible una diferencia así cuando dos series de valores (X e Y) tienen demasiada diferencia en el orden de los valores.