Aiuta a scrivere una regressione lineare - pagina 5

 
Rosh писал (а) >>

E questo è quello che Excel 2007 dà



Quindi, potrebbe essere necessario controllare Matcad.

Se ho capito bene, Excel dà il 3° risultato, diverso dai primi due ). Dov'è la verità? B è lo stesso di Matcad, ma il coefficiente A è diverso.

 
Prival писал (а) >>

Se ho capito bene, allora Excel ha dato il 3° risultato, diverso dai primi due). Dov'è la verità? B è lo stesso di Matcad, ma il coefficiente A è diverso.

In generale, con così tante cifre significative e un tale intervallo, i calcoli vanno da qualche parte nella parte posteriore della mantissa. Cioè, anche elementi di casualità possono essere introdotti nella risposta. Penso che ci si possa aspettare la correttezza solo per qualche algoritmo speciale di alta precisione. In questo caso è meglio spostare l'origine delle coordinate più vicino alla gamma X .



P.S. Soprattutto quando si calcola la somma di X*X, l'informazione va direttamente nel cesso :)

 
lna01 писал (а) >>

Generalmente, con così tante cifre significative e un tale intervallo, i calcoli vanno da qualche parte nella parte posteriore della mantissa. Cioè, anche elementi di casualità possono essere introdotti nella risposta. Penso che si possa contare sulla correttezza solo per qualche algoritmo speciale con una maggiore precisione. Ma in questo caso è meglio spostare l'origine delle coordinate più vicino alla gamma X.

La questione è che ho iniziato a preparare il campionato. Ho iniziato a tradurre i miei sviluppi in Matkadec in MQL. Se vi ricordate, stavamo costruendo l'ACF (funzione di autocorrelazione) e ho iniziato con questo e ho deciso di usare formule dirette, poiché ho messo troppo carico sulla CPU tramite le trasformate di Fourier.

Ecco perché ho iniziato ad analizzare dove il problema ha iniziato a crescere.

Cercherò di spostare X (Tempo) a 0. Ma dovrò ricontrollare tutto di nuovo. Devo già rinunciare a circa il 50% delle mie idee.

 
Prival писал (а) >>

Il fatto è che ho iniziato a preparare il campionato. E ho iniziato a trasferire i miei sviluppi in Matcadet a MQL. Se vi ricordate, stavamo costruendo l'ACF (funzione di autocorrelazione), ho iniziato con essa e ho deciso di calcolarla usando formule dirette, poiché le trasformate di Fourier sono un carico pesante per il processore.

Ecco perché ho iniziato ad analizzare dove il problema ha iniziato a crescere.

Cercherò di spostare X (Tempo) a 0. Ma dovrò ricontrollare tutto di nuovo. Così com'è, devo già rinunciare al 50% delle mie idee

MT mantiene 15 cifre nella mantissa. Se estraiamo la radice otteniamo 10^7. Cioè, bisogna elevare al quadrato e sommare i numeri superiori a 10000000, vedi il poscritto del post precedente :). Fortunatamente, questo limite corrisponde al numero di barre di minuti nella storia reale, quindi se è così, dovrebbe ancora funzionare. Ma se è il tempo, allora uno spostamento dell'origine delle coordinate è semplicemente inevitabile.


P.S. A proposito, se avete intenzione di usare la vostra funzione sul campionato, aggiungete la protezione contro la divisione per zero. Altrimenti c'è il rischio che il vostro indicatore si fermi a metà del campionato. O all'inizio. Ricordate, c'era una cosa simile con Fourier.

 

Lo stesso algoritmo in 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);
}
}


Risultato:


intercetta = -3.3333333333333335 pendenza = 5.0
intercetta = -1102.169141076954 pendenza = 9.075536028198574E-7

Processo terminato con codice di uscita 0

 

Rosh

Sono d'accordo che queste formule daranno lo stesso risultato ecco il matcad

Vedo che i risultati coincidono con MQL e Java, ma matcad non mi ha mai deluso prima, quindi ho dei dubbi. Ho controllato e ordinato i risultati.

Ho controllato e ordinato per X e ho calcolato di nuovo i coefficienti.

Il risultato è cambiato!!!, questo non dovrebbe essere il caso. Molto probabilmente l'errore è dovuto all'accumulo di errori dovuti alla quadratura di grandi numeri(Candid ha ragione). Ho studiato la letteratura e ho trovato una formula più semplice, senza quadratura e apparentemente con meno calcoli.

Il risultato è lo stesso che in matcad, e non dipende dall'ordinamento.

Vi consiglio di usare questa formula per calcolare i coefficienti di regressione lineare.

//+------------------------------------------------------------------+
//|                                                       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 allegato, se qualcuno pulirà LinearRegr (per evitare errori quando si lavora con dati reali e per aumentare le prestazioni), sarà buono. Ho scambiato A e B, perché

La notazione y(x)=a*x+b è più familiare (per me dai libri).

File:
linreg_1.mq4  2 kb
 

Non vedo come il risultato possa dipendere dall'ordinamento. L'ordinamento non è usato esplicitamente da nessuna parte nelle formule.


Inoltre, quest'ultimo algoritmo utilizza i valori di aspettativa di X e Y e potenzialmente può anche introdurre un errore nei calcoli. E un'altra cosa: è improbabile che usare due cicli contro uno migliori le prestazioni.


Se abbiamo bisogno di eseguire massicci calcoli di regressione lineare su un certo numero di sequenze di prezzi, è meglio selezionare buffer separati in un indicatore e calcolare utilizzando il metodo del totale cumulativo. Permette di accelerare i calcoli di ordini di grandezza. Esempio - Kaufman AMA ottimizzato: Perry Kaufman AMA ottimizzato

 
Rosh писал (а) >>

Non vedo come il risultato possa dipendere dall'ordinamento. L'ordinamento non è usato esplicitamente da nessuna parte nelle formule.


Inoltre, l'ultimo algoritmo usa l'aspettativa dei valori X e Y, e potenzialmente può anche introdurre qualche errore nei calcoli. Un'altra cosa: usare due cicli contro uno difficilmente migliorerebbe le prestazioni.

Se abbiamo bisogno di fare i calcoli di massa della regressione lineare per un certo numero di sequenze di prezzi, è meglio selezionare buffer separati in un indicatore e utilizzare il metodo di totalizzazione cumulativa. Permette di accelerare i calcoli di ordini di grandezza. Esempio - Kaufman AMA ottimizzato: Perry Kaufman AMA ottimizzato

1. Il punto è che il risultato non dovrebbe dipendere dall'ordinamento, mentre l'algoritmo sì. Guarda qui.

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

Il risultato è

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

Questo non dovrebbe essere il caso.

Vedo che appaiono due loop, ecco perché ho chiesto prestazioni più veloci. L'algoritmo "Regression: what is it?" può essere più veloce, ma dovremmo anche ottimizzarlo (penso che Vinin l'abbia già fatto).

3. Grazie per Kaufmann, è un buon indicatore. Nel caso in cui non l'abbiate dimenticato, prima della seconda di campionato ci stavo prendendo delle imprecisioni. Grazie per averli corretti.

Z.U. Per favore chi hala matematica. Digita questi array e calcola le formule incorporate (per quanto mi ricordi, ci sono), e pubblica qui il risultato. Per arrivare a un consenso. Grazie. Aiuto )). Rosh è piuttosto difficile da convincere, ma anche io ho una fronte militare )))

 
Prival писал (а) >>

2. Vedo che appaiono due loop, è per questo che ho chiesto un'accelerazione. L'algoritmo 'Regression: what is it?' può essere più veloce ma dovremmo ottimizzare anche questo (penso che Vinin l'abbia già fatto).

LWMA è effettivamente più sicuro di X*X, quindi il tuo lavoro con Mathemat assume un nuovo significato :). Ma continuo a considerare la mia prima raccomandazione (spostare l'origine delle coordinate) come l'opzione migliore. La sostituzione formale di Time[pos] con Time[pos]-Time[Bars-1] è ovunque un tale rischio di errore?

 
Prival писал (а) >>

1. Questo è il punto: il risultato non dovrebbe dipendere dall'ordinamento, ma in quell'algoritmo sì. Guarda qui.

Risultato

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

Questo non dovrebbe essere il caso.



Inserisci la ristrintokwa nel tuo codice:

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

Prendi qualcosa come questo:

prima chiamata
sumY = 11.98130000 sumX = 7299840060.000000 sumXY = 14576928951.87000100 sumX2 = 8881277483596863500.000000
sommaXY*dN-sommaX*sommaY = 0,34199524
sommaX2*dN-sommaX*sommaX = 376832.00000000
A = -1102.16914108 B = 0.00000091
seconda chiamata
sumY = 11.98130000 sumX = 7299840060.000000 sumXY = 14576928951.87000300 sumX2 = 8881277483596864500.000000
sommaXY*dN-sommaX*sommaY = 0,34202576
sommaX2*dN-sommaX*sommaX = 385024.00000000
A = -1078.77267965 B = 0.00000089

Questa è un'altra insidia dei calcoli del computer e degli arrotondamenti. Da un lato io stesso non mi aspettavo un tale rastrellamento, ma dall'altro una tale differenza è comprensibile quando due serie di valori (X e Y) hanno troppa differenza nell'ordine dei valori.

Motivazione: