Aide à la rédaction d'une régression linéaire - page 5

 
Rosh писал (а) >>

Et voici ce que donne Excel 2007



Il pourrait donc être nécessaire de vérifier Matcad.

Si je comprends bien, Excel donne le 3ème résultat, différent des deux premiers). Où est la vérité ? B est le même que Matcad, mais le coefficient A est différent.

 
Prival писал (а) >>

Si je comprends bien, alors Excel a donné le 3ème résultat, différent des deux premiers). Où est la vérité ? B est le même que dans Matcad, mais le coefficient A est différent.

En général, avec autant de chiffres significatifs et une telle plage, les calculs vont quelque part à l'arrière de la mantisse. C'est-à-dire que même des éléments de hasard peuvent être introduits dans la réponse. Je pense que l'exactitude ne peut être attendue que pour certains algorithmes spéciaux de haute précision. Dans ce cas, il est préférable de rapprocher l'origine des coordonnées de la plage X .



P.S. Surtout quand on calcule la somme de X*X, l'information va directement dans les toilettes :)

 
lna01 писал (а) >>

En général, avec autant de chiffres significatifs et une telle plage, les calculs se font quelque part à l'arrière de la mantisse. C'est-à-dire que même des éléments de hasard peuvent être introduits dans la réponse. Je pense que l'on ne peut compter sur l'exactitude que pour certains algorithmes spéciaux avec une précision accrue. Mais dans ce cas, il est préférable de déplacer l'origine des coordonnées plus près de la plage X.

Le fait est que j'ai commencé à me préparer pour le championnat. J'ai commencé à traduire mes développements dans Matkadec en MQL. Si vous vous souvenez, nous étions en train de construire l'ACF (fonction d'autocorrélation) et j'ai commencé avec elle et j'ai décidé d'utiliser des formules directes, car je chargeais trop le CPU via les transformées de Fourier.

C'est pourquoi j'ai commencé à analyser où le problème a commencé à se développer.

Je vais essayer de faire passer X (temps) à 0. Mais je vais devoir tout revérifier à nouveau. Je dois déjà renoncer à environ 50 % de mes idées.

 
Prival писал (а) >>

Le fait est que j'ai commencé à me préparer pour le championnat. Et j'ai commencé à transférer mes développements dans Matcadet vers MQL. Si vous vous souvenez, nous construisions l'ACF (fonction d'autocorrélation), j'ai commencé avec elle et j'ai décidé de la calculer en utilisant des formules directes, puisque les transformées de Fourier sont une lourde charge pour le processeur.

C'est pourquoi j'ai commencé à analyser où le problème a commencé à se développer.

Je vais essayer de faire passer X (Temps) à 0. Mais je vais devoir tout revérifier à nouveau. En l'état actuel des choses, je dois déjà abandonner 50 % de mes idées.

MT conserve 15 chiffres dans la mantisse. Si on extrait la racine, on obtient 10^7. C'est-à-dire qu'il faut élever au carré et additionner des nombres supérieurs à 10000000, voir post-scriptum au post précédent :). Heureusement, cette limite correspond au nombre de barres de minutes dans l'historique réel, donc si c'est le cas, cela devrait quand même fonctionner. Mais si c'est le temps, alors un déplacement de l'origine des coordonnées est tout simplement inévitable.


P.S. Au fait, si vous comptez utiliser votre fonction sur le championnat, ajoutez une protection contre la division par zéro. Sinon, il y a un risque que votre indicateur se retrouve au milieu du championnat. Ou au début. Rappelez-vous, il y avait une telle chose avec Fourier.

 

Le même algorithme 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);
}
}


Résultat :


intercept = -3.3333333333333335 slope = 5.0
intercept = -1102.169141076954 slope = 9.075536028198574E-7

Le processus s'est terminé avec le code de sortie 0

 

Rosh

Je suis d'accord que ces formules donneront le même résultat voici matcad

Je vois que les résultats coïncident avec MQL et Java, mais matcad ne m'a jamais fait défaut auparavant, donc j'ai des doutes. Je l'ai vérifié et j'ai trié les résultats.

Je l'ai vérifié et trié par X et j'ai calculé les coefficients à nouveau.

Le RESULTAT a changé ! !!, cela ne devrait pas être le cas. L'erreur est très probablement due à l'accumulation d'erreurs due à l'élévation au carré de grands nombres(Candid a raison). J'ai fait des recherches dans la littérature et j'ai trouvé une formule plus simple, sans équarrissage et apparemment moins de calculs.

Le résultat est le même que dans matcad, et il ne dépend pas du tri.

Je recommande d'utiliser cette formule pour calculer les coefficients de régression linéaire.

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

Script joint, si quelqu'un peut nettoyer LinearRegr (pour éviter les erreurs lors du travail avec des données réelles et pour augmenter les performances), ce sera bien. J'ai interchangé A et B, parce que

La notation y(x)=a*x+b m'est plus familière (grâce aux livres).

Dossiers :
linreg_1.mq4  2 kb
 

Je ne vois pas comment le résultat peut dépendre du tri. Le tri n'est utilisé explicitement nulle part dans les formules.


En outre, ce dernier algorithme utilise les valeurs attendues de X et Y et peut potentiellement introduire une erreur dans les calculs. Autre chose : il est peu probable que l'utilisation de deux boucles contre une seule améliore les performances.


Si nous devons effectuer des calculs massifs de régression linéaire sur un certain nombre de séquences de prix, il est préférable de sélectionner des tampons séparés dans un indicateur et de faire le calcul en utilisant la méthode du total cumulé. Il permet d'accélérer les calculs par des ordres de grandeur. Exemple - Kaufman AMA optimisé : Perry Kaufman AMA optimisé

 
Rosh писал (а) >>

Je ne vois pas comment le résultat peut dépendre du tri. Le tri n'est utilisé explicitement nulle part dans les formules.


En outre, le dernier algorithme utilise l'espérance des valeurs X et Y, ce qui peut potentiellement introduire des erreurs dans les calculs. Une dernière chose : utiliser deux boucles contre une seule n'améliorerait guère les performances.

Si nous devons effectuer les calculs de masse de la régression linéaire pour un certain nombre de séquences de prix, il est préférable de sélectionner des tampons séparés dans un indicateur et d'utiliser la méthode de totalisation cumulative. Il permet d'accélérer les calculs par des ordres de grandeur. Exemple - Kaufman AMA optimisé : Perry Kaufman AMA optimisé

1. L'idée est que le résultat ne doit pas dépendre du tri, alors que l'algorithme le fait. Regardez ça.

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

Le résultat est

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

Cela ne devrait pas être le cas.

Je peux voir que deux boucles apparaissent, c'est pourquoi j'ai demandé des performances plus rapides. L'algorithme "Régression : qu'est-ce que c'est ?" est peut-être plus rapide, mais nous devrions l'optimiser aussi (je pense que Vinin l'a déjà fait).

3. Merci pour Kaufmann, c'est un bon indicateur. Au cas où vous ne l'auriez pas oublié, avant le deuxième championnat, j'y relevais des inexactitudes. Merci de les avoir corrigés.

Z.U. Je demande qui ales Maths. Tapez ces tableaux et calculez les formules intégrées (pour autant que je me souvienne, il y en a), et postez le résultat ici. Afin de parvenir à un consensus. Merci. Aide )). Rosh est assez difficile à convaincre, mais j'ai aussi un front militaire ))))

 
Prival писал (а) >>

2. je vois que deux boucles apparaissent, c'est pourquoi j'ai demandé une accélération. L'algorithme "Régression : qu'est-ce que c'est ?" est peut-être plus rapide mais nous devrions l'optimiser aussi (je pense que Vinin l'a déjà fait).

LWMA est effectivement plus sûr que X*X, donc votre travail avec Mathemat prend un nouveau sens :). Mais je considère toujours ma première recommandation (déplacer l'origine des coordonnées) comme la meilleure option. Le remplacement formel de Time[pos] par Time[pos]-Time[Bars-1] partout présente-t-il un tel risque d'erreur ?

 
Prival писал (а) >>

1. C'est là le problème : le résultat ne devrait pas dépendre du tri, mais dans cet algorithme, c'est le cas. Regardez ça.

Résultat

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

Cela ne devrait pas être le cas.



Insérez le ristrintokwa dans votre code :

//-------------------------------------------------------------------------------
// использование этой формулы приводит к ошибкам если 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;
}

Obtenez quelque chose comme ça :

premier appel
sumY = 11.98130000 sumX = 7299840060.00000000 sumXY = 14576928951.87000100 sumX2 = 8881277483596863500.00000000
sumXY*dN-sumX*sumY = 0.34199524
sumX2*dN-sumX*sumX = 376832.00000000
A = -1102.16914108 B = 0.00000091
deuxième appel
sumY = 11.98130000 sumX = 7299840060.00000000 sumXY = 14576928951.87000300 sumX2 = 8881277483596864500.00000000
sumXY*dN-sumX*sumY = 0,34202576
sumX2*dN-sumX*sumX = 385024.00000000
A = -1078.77267965 B = 0.00000089

Il s'agit d'un autre piège des calculs informatiques et des arrondis. D'une part, je ne m'attendais pas à un tel rake, mais d'autre part, une telle différence est compréhensible lorsque deux séries de valeurs (X et Y) ont une trop grande différence dans l'ordre des valeurs.