線形回帰の記述を支援する - ページ 5

 
Rosh писал (а)>>

そして、Excel 2007ではこのように表示されます。



そのため、Matcadを確認する必要があるかもしれません。

私の理解が正しければ、Excelは最初の2つとは異なる3つ目の結果を出します)。真実はどこにあるのか?BはMatcadと同じですが、係数Aは異なります。

 
Prival писал (а)>>

もし私が正しく理解していれば、Excelは最初の2つとは異なる3つ目の結果を出しました)。真実はどこにあるのか?B は Matcad と同じですが、係数 A は異なります。

一般に、有効桁数が多く、このような範囲では、計算は仮数の後ろのどこかに行ってしまいます。つまり、答えの中にランダムな要素さえも入り込む可能性がある。正しさが期待できるのは、精度の高い特殊なアルゴリズムの場合だけだと思います。この場合、座標の原点をXレンジ に近づけた方がよいでしょう。



追伸:特にX*Xの和を計算する場合、情報はそのままトイレに流れます :)

 
lna01 писал (а)>>

一般に、有効桁数が多く、このような範囲では、仮数の後ろのどこかで計算が行われます。つまり、答えにランダムな要素さえも取り入れることができるのです。正しさは、精度を高めた何か特別なアルゴリズムにしか期待できないと思うのです。しかし、この場合、座標の原点をXの範囲に近づけた方が良い

問題は、チャンピオンシップの準備を始めたことだ。Matkadecで開発したものをMQLに 翻訳し始めたのです。思い起こせば、ACF(自己相関関数)を作っていたのですが、フーリエ変換によるCPUへの負荷が大きいので、まずは直接式を使うことにしたんです。

そのため、どこからが問題なのかを分析するようになったのです。

X(時間)を0にシフトしてみる。しかし、もう一度すべてを再確認する必要がありますね。すでにアイデアの50%くらいはあきらめなければならないのです。

 
Prival писал (а)>>

チャンピオンシップの準備を始めたということです。そして、Matcadetで開発したものをMQLに 転送するようになったのです。思い起こせば、ACF(自己相関関数)を作っていたのですが、フーリエ変換はプロセッサへの負荷が大きいので、直接式で計算することにして、始めました。

そのため、どこからが問題なのかを分析するようになったのです。

X(時間)を0にシフトしてみる。しかし、もう一度すべてを再確認する必要がありますね。このままでは、すでに自分のアイデアの50%を諦めなければならない。

MTは仮数部に15桁を保持する。根を抜き出すと10^7になる。つまり、10000000より大きい数を二乗して合計する必要があります、前回の記事の追記を参照 :)。幸い、その制限は実際の履歴の分バーの数に対応しているので、それであれば、まだ動くはずです。しかし、それが時間であるならば、座標原点の移動は必然であるとしか言いようがありません。


P.S. ところで、もしあなたが作成した関数をチャンピオンシップで使用するのであれば、ゼロによる除算に対する保護を追加してください。そうでないと、インジケーターがチャンピオンシップの真ん中に立っているだけになってしまう危険性があります。あるいは冒頭で。フーリエの時もそんなことがあったことを思い出してください。

 

同じアルゴリズムを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);
}
}


結果


切片 = -3.333333333335 傾き = 5.0
切片 = -1102.169141076954 傾き = 9.075536028198574E-7

終了コード0でのプロセス終了

 

ロッシュ

これらの式が同じ結果を与えることに同意します。

MQLとJavaで結果が一致するのはわかりますが、matcadは今まで失敗したことがないので、疑問がありますね。確認し、結果をソートしてみました。

それを確認し、X でソートして、再度係数を計算しました。

RESULTが変わってしまった!!!こんなはずじゃなかったのに。大きな数値を二乗することによる誤差の蓄積が原因である可能性が高い(Candid の言うとおり)。文献を調べると、もっとシンプルな式で、二乗もなく、計算も少なそうなものがありました。

結果はmatcadと同じで、ソートには依存しない。

線形回帰係数の計算には、この計算式を使うことをお勧めします。

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

添付のスクリプトですが、誰かがLinearRegrをクリーンアップ(実データを扱う際のエラー防止とパフォーマンス向上)してくれれば、良いのですが。Aと Bを 入れ替えたのは

y(x)=a*x+b という表記の方が(本で見て)馴染みがあります。

ファイル:
linreg_1.mq4  2 kb
 

ソートによって結果が左右されるとは思えません。ソートは計算式のどこにも明示的に使用されていません。


また、後者のアルゴリズムでは、XとYの期待値を用いるため、計算に誤差が生じる可能性がある。そしてもうひとつ、1つのループに対して2つのループを使っても、パフォーマンスの向上は望めません。


もし、多くの価格シーケンスに対して大規模な線形回帰計算を行う必要がある場合は、インジケータで別々のバッファを選択し、累積合計法を使用して計算する方がよいでしょう。これにより、計算を桁違いに 高速化することができます。例)Kaufman AMA optimized : ペリー・カウフマン AMA optimized

 
Rosh писал (а)>>

ソートによって結果が左右されるとは思えません。ソートは計算式のどこにも明示的に使用されていません。


また、最後のアルゴリズムは、XとYの値の期待値を使用し、潜在的に計算でいくつかのエラーが発生する可能性があります。もうひとつ、1つのループに対して2つのループを使っても、ほとんど性能は上がりません。

もし、多くの価格配列に対して線形回帰の一括計算をする必要がある場合は、指標で別々のバッファを選択し、累積積算法を使用する方がよいでしょう。これにより、計算を桁違いに 高速化することができます。例)Kaufman AMA optimized : ペリー・カウフマン AMA optimized

1.ポイントは、結果はソートに依存してはいけないが、アルゴリズムには依存するということです。チェックしてみてください。

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

その結果

2008.07.30 13:51:08 LinReg EURUSD,M1:A= 0.00000090B= -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

これではいけないと思います。

ループが2つ表示されているのがわかるので、高速化を求めたわけです。Regression: what is it?」 アルゴリズムの方が速いかもしれませんが、こちらも最適化すべきです(Vininが 既にやっていると思います)。

3.カウフマンに感謝、良い指標になりますね。第2回大会の前に忘れてはいけないのは、私はその不正確な情報をキャッチしていたことです。訂正していただき、ありがとうございます。

Z.U.私は、「数学は 誰が持っているのか」と聞いています。これらの配列を入力し、内蔵の計算式(覚えている限りではある)で計算し、その結果をここに投稿してください。合意形成のためにありがとうございます。ヘルプ ))。ロッシュはかなり説得力がありますが、私も軍人のおでこを持つので )))

 
Prival писал (а)>>

2.ループが2つ出ているのがわかるので、高速化をお願いした次第です。Regression: what is it?」 アルゴリズムの方が速いかもしれませんが、こちらも最適化すべきです(Vininが 既にやっていると思います)。

LWMAはX*Xよりも確かに安全なので、Mathematicsとの 連携は新しい意味を持ちますね :) 。しかし、私は今でも最初の提案(座標の原点をずらす)を最良の選択肢だと考えています。Time[pos]をTime[pos]-Time[Bars-1]に形式的に置き換えることは、どこでもそんなに間違う危険があるのでしょうか?

 
Prival писал (а)>>

1.それは、結果はソートに依存しないはずなのに、そのアルゴリズムでは依存してしまうということです。チェックしてみてください。

結果

2008.07.30 13:51:08 LinReg EURUSD,M1:A= 0.00000090B= -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

これではいけないと思います。



リストラントクワをコードに挿入してください。

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

このようなものを入手してください。

ファーストコール
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
セカンドコール
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

これもコンピュータ計算と四捨五入の落とし穴です。私自身はこのようなレーキは予想していなかったが、一方で、2つの値の系列(XとY)の値の順序があまりに異なる場合、このような差が生じるのは理解できる。